Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
MIT License

Copyright (c) 2020-2024 Estonian Information System Authority
Copyright (c) 2020-2025 Estonian Information System Authority

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
35 changes: 30 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,6 @@ The Web eID extension for Safari is built as a [Safari web extension](https://de
TOKEN_SIGNING_BACKWARDS_COMPATIBILITY=true npm run clean build package
```

During development, for additional logging, set the `DEBUG` environment variable to `true`.
```bash
DEBUG=true npm run clean build package
```

5. Load in Firefox as a Temporary Extension
1. Open `about:debugging#/runtime/this-firefox`
2. Click "Load temporary Add-on..." and open `/web-eid-webextension/dist/manifest.json`
Expand All @@ -62,3 +57,33 @@ The Web eID extension for Safari is built as a [Safari web extension](https://de
Make sure the `NATIVE_APP_NAME` value in `src/config.ts` matches the one in
the Web-eID native application manifest file.

### Developer tools

The Web eID DevTools tab can be useful while integrating Web eID on a website.

#### Features
- Event history between the website, extension and native application.
- Extension's internal log messages.
- Option to override extension settings, without needing to compile the extension yourself.
- Option to allow the http://localhost origin when authenticating and signing

#### Enable or disable the Web eID developer tools tab

**Firefox**
1. Open [Menu -> Settings -> Extensions and themes]
or navigate to the address `about:addons`
2. Open the Web eID extension details
3. Open the "Permissions" tab
4. Toggle "Extend developer tools to access your data in open tabs"

**Chrome**
1. Open [Settings -> Extensions]
or navigate to the address `chrome://extensions/`
2. Open the Web eID extension details
3. Open "Extension options"
4. Toggle "Enable developer tools"

**Safari**
1. Open [Settings -> Extensions]
2. Open the Web eID Settings
3. Toggle "Enable developer tools"
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "web-eid-webextension",
"version": "2.4.1",
"version": "2.4.2-rc1",
"description": "",
"main": "src/index.js",
"scripts": {
Expand Down
7 changes: 2 additions & 5 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,26 @@ import license from "rollup-plugin-license";
import polyfill from "rollup-plugin-polyfill";
import resolve from "@rollup/plugin-node-resolve";

const projectRootDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)));

// List of browsers to build for.
const browsers = ["chrome", "firefox", "safari"];

const processEnvConf = {
DEBUG: process.env.DEBUG,
TOKEN_SIGNING_BACKWARDS_COMPATIBILITY: process.env.TOKEN_SIGNING_BACKWARDS_COMPATIBILITY,
}

const pluginsConf = (environment) => [
alias({
entries: [{
find: "@web-eid.js",
replacement: path.resolve(projectRootDir, "dist/lib/web-eid.js/src"),
replacement: path.resolve(import.meta.dirname, "dist/lib/web-eid.js/src"),
}],
}),
resolve({ rootDir: "./dist" }),
cleanup({ comments: ["jsdoc"] }), // Keep jsdoc comments
license({
banner: {
content: {
file: path.join(projectRootDir, "LICENSE"),
file: path.join(import.meta.dirname, "LICENSE"),
encoding: "utf-8",
},
},
Expand Down
16 changes: 15 additions & 1 deletion scripts/build.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -111,10 +111,24 @@ const targets = {
await cp("./static/icons", "./dist/safari");

rem(
"Copying static consent pages to Firefox dist directory"
"Copying static pages to Firefox dist directory"
);
await cp("./static/_locales", "./dist/firefox/_locales");
await cp("./static/views", "./dist/firefox/views");
await rm("./dist/firefox/views/options.*");
await cp("./node_modules/webextension-polyfill/dist/browser-polyfill.min.js", "./dist/firefox/views/browser-polyfill.min.js");

rem(
"Copying static pages to Chrome dist directory"
);
await cp("./static/views", "./dist/chrome/views");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do the Firefox consent pages end up in Chrome as well with this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, installed.html+js ends up in the chrome build, but aren't used. This should be fixed.

await cp("./node_modules/webextension-polyfill/dist/browser-polyfill.min.js", "./dist/chrome/views/browser-polyfill.min.js");

rem(
"Copying static pages to Safari dist directory"
);
await cp("./static/views", "./dist/safari/views");
await cp("./node_modules/webextension-polyfill/dist/browser-polyfill.min.js", "./dist/safari/views/browser-polyfill.min.js");

rem(
"Setting up the Firefox manifest"
Expand Down
2 changes: 1 addition & 1 deletion src/background-firefox/consent.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2024 Estonian Information System Authority
* Copyright (c) 2020-2025 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down
26 changes: 21 additions & 5 deletions src/background-safari/services/NativeAppService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2024 Estonian Information System Authority
* Copyright (c) 2020-2025 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -27,7 +27,11 @@ import libraryConfig from "@web-eid.js/config";

import Mutex from "../../shared/Mutex";
import calculateJsonSize from "../../shared/utils/calculateJsonSize";
import config from "../../config";
import { config } from "../../shared/configManager";

import Logger from "../../shared/Logger";

const logger = new Logger("NativeAppService.ts");

type NativeAppPendingRequest =
| { resolve?: (value: PromiseLike<any>) => void; reject?: (reason?: any) => void }
Expand All @@ -47,7 +51,13 @@ export default class NativeAppService {

private pending: NativeAppPendingRequest = null;

constructor(tabId?: number) {
logger.tabId = tabId;
}

async connect(): Promise<{ version: string }> {
logger.log("Connecting to the native application " + config.NATIVE_APP_NAME);

this.state = NativeAppState.CONNECTING;

try {
Expand All @@ -71,6 +81,8 @@ export default class NativeAppService {
if (message.version) {
this.state = NativeAppState.CONNECTED;

logger.info("Connected to the native application", message);

return message;
}

Expand All @@ -91,7 +103,8 @@ export default class NativeAppService {
}

close(error?: any): void {
config.DEBUG && console.log("Disconnecting from native app");
logger.info("Closing connection to native application");

this.state = NativeAppState.DISCONNECTED;

this.pending?.reject?.(error);
Expand All @@ -111,6 +124,8 @@ export default class NativeAppService {
setTimeout(() => { reject(throwAfterTimeout); }, timeout );

const onResponse = (message: any): void => {
logger.log("Response from native application", message);

this.pending = null;

if (message.error) {
Expand All @@ -120,13 +135,14 @@ export default class NativeAppService {
}
};

config.DEBUG && console.log("Sending message to native app", JSON.stringify(message));

const messageSize = calculateJsonSize(message);

logger.info("Calculated message size", messageSize);

if (messageSize > config.NATIVE_MESSAGE_MAX_BYTES) {
throw new Error(`native application message exceeded ${config.NATIVE_MESSAGE_MAX_BYTES} bytes`);
}
logger.log("Sending message to native application", message);

browser.runtime.sendNativeMessage("application.id", message, onResponse);
});
Expand Down
2 changes: 1 addition & 1 deletion src/background/actions/TokenSigning/errorToResponse.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2024 Estonian Information System Authority
* Copyright (c) 2020-2025 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down
33 changes: 26 additions & 7 deletions src/background/actions/TokenSigning/getCertificate.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2024 Estonian Information System Authority
* Copyright (c) 2020-2025 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down Expand Up @@ -30,27 +30,42 @@ import {
} from "../../../models/TokenSigning/TokenSigningResponse";

import ByteArray from "../../../shared/ByteArray";
import { MessageSender } from "../../../models/Browser/Runtime";
import NativeAppService from "../../services/NativeAppService";
import config from "../../../config";
import { config } from "../../../shared/configManager";
import errorToResponse from "./errorToResponse";
import threeLetterLanguageCodes from "./threeLetterLanguageCodes";
import tokenSigningResponse from "../../../shared/tokenSigningResponse";

import Logger from "../../../shared/Logger";

const logger = new Logger("TokenSigning/getCertificate.ts");

export default async function getCertificate(
sender: MessageSender,
nonce: string,
sourceUrl: string,
lang?: string,
filter: "AUTH" | "SIGN" = "SIGN",
): Promise<TokenSigningCertResponse | TokenSigningErrorResponse> {
logger.tabId = sender.tab?.id;

logger.log("Certificate requested");

if (lang && Object.keys(threeLetterLanguageCodes).includes(lang)) {
lang = threeLetterLanguageCodes[lang];
logger.log("Language code converted to three-letter code", lang);
}

const nativeAppService = new NativeAppService();
const nativeAppService = new NativeAppService(sender.tab?.id);

logger.info("Checking 'filter', should be 'SIGN'");

if (filter !== "SIGN") {
const { message, name, stack } = new Error("Web-eID only allows signing with a signing certificate");

logger.error({ message, name, stack });

return tokenSigningResponse<TokenSigningErrorResponse>("not_allowed", nonce, {
message,
name,
Expand All @@ -59,9 +74,7 @@ export default async function getCertificate(
}

try {
const nativeAppStatus = await nativeAppService.connect();

config.DEBUG && console.log("Get certificate: connected to native", nativeAppStatus);
await nativeAppService.connect();

const message: NativeGetSigningCertificateRequest = {
command: "get-signing-certificate",
Expand All @@ -80,14 +93,20 @@ export default async function getCertificate(
);

if (!response?.certificate) {
logger.info("Certificate request failed. Expected 'certificate' was not found in the response");

return tokenSigningResponse<TokenSigningErrorResponse>("no_certificates", nonce);
} else {
logger.info("Returning success response");

return tokenSigningResponse<TokenSigningCertResponse>("ok", nonce, {
cert: new ByteArray().fromBase64(response.certificate).toHex(),
});
}
} catch (error) {
console.error(error);
logger.info("Certificate request failed");
logger.error(error);

return errorToResponse(nonce, error);
} finally {
nativeAppService.close();
Expand Down
2 changes: 1 addition & 1 deletion src/background/actions/TokenSigning/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020-2024 Estonian Information System Authority
* Copyright (c) 2020-2025 Estonian Information System Authority
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
Expand Down
Loading