Skip to content

Commit

Permalink
breaking: migrates to @ssasy-auth/[email protected] (v1.0.0)
Browse files Browse the repository at this point in the history
- [breaking] renames challenge response variables and functions in bridge
- updates references in `WalletStore` to reflect new core version
- improves logging and error description
- adds `changelog` to extension bridge library
  • Loading branch information
this-oliver committed Sep 9, 2023
1 parent ae73180 commit 2d1e6dd
Show file tree
Hide file tree
Showing 22 changed files with 526 additions and 346 deletions.
11 changes: 11 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

> Only notable changes are documented here. You can find the changelog for the `@ssasy-auth/extension` package at [src/bridge/docs/CHANGELOG.md](../src/bridge/docs/changelog.md).
## `1.0.0`

- updates `@ssasy-auth/core` to `2.2.3` which enables SSASy URIs

## `0.23.10`

- renames `REQUEST_SOLUTION` message type (in [types.ts](../src/bridge/src/types.ts)) to `REQUEST_CHALLENGE_RESPONSE` to better reflect the purpose of the message.
16 changes: 8 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
{
"name": "@ssasy-auth/extension",
"nickname": "ssasy",
"version": "0.23.9",
"version": "1.0.0",
"license": "MIT",
"description": "A browser extension that offers a secure and usable alternative to passwords and federated identity providers.",
"repository": "this-oliver/ssasy-ext",
"author": "[email protected]",
"scripts": {
"bridge:build": "tsc -p src/bridge/tsconfig.json",
"bridge:pack": "esno scripts/prepare-bridge.ts",
"bridge:prepare": "run-s test bridge:build bridge:pack",
"bridge:release": "pnpm bridge:prepare && cd src/bridge && npm publish --access public && cd ../../ && pnpm bridge:clear",
"bridge:preview": "pnpm bridge:prepare && cd src/bridge && npm pack && cd ../../ && pnpm bridge:clear",
"bridge:clear": "rimraf src/bridge/package.json src/bridge/*-lock.* src/bridge/lib src/bridge/node_modules",
"bridge:prepare": "esno scripts/prepare-bridge.ts",
"bridge:pack": "run-s test bridge:clear bridge:prepare bridge:build",
"bridge:release": "pnpm bridge:pack && cd src/bridge && npm publish --access public && cd ../../ && pnpm bridge:clear",
"bridge:preview": "pnpm bridge:pack && cd src/bridge && npm pack && cd ../../ && pnpm bridge:clear",
"bridge:clear": "rimraf src/bridge/lib src/bridge/node_modules src/bridge/package.json src/bridge/*-lock.*",
"build": "cross-env NODE_ENV=production run-s clear test build:web build:prepare build:js",
"build:mv3": "cross-env NODE_ENV=production MANIFEST_VERSION=3 run-s clear test build:web build:prepare build:js build:bg",
"build:prepare": "esno scripts/prepare.ts",
Expand Down Expand Up @@ -43,7 +43,7 @@
},
"dependencies": {
"@mdi/js": "^7.2.96",
"@ssasy-auth/core": "1.9.1",
"@ssasy-auth/core": "^3.0.0",
"pinia": "^2.0.33",
"vue": "^3.2.47",
"vue-router": "4",
Expand Down Expand Up @@ -97,4 +97,4 @@
"*.ts": "eslint --fix"
},
"packageManager": "[email protected]"
}
}
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

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

6 changes: 3 additions & 3 deletions shim.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { MessageType } from '~/bridge'
import type { KeyRequest, PublicKeyResponse, ChallengeRequest, ChallengeResponse, ErrorResponse } from '~/bridge'

declare module 'webext-bridge' {

// define message protocol types below (see https://github.com/antfu/webext-bridge#type-safe-protocols)
export interface ProtocolMap {
'close-request-tab': ErrorResponse | undefined
'close-popup': ErrorResponse | undefined
[MessageType.REQUEST_PUBLIC_KEY]: ProtocolWithReturn<KeyRequest, PublicKeyResponse | ErrorResponse>
[MessageType.REQUEST_SOLUTION]: ProtocolWithReturn<ChallengeRequest, ChallengeResponse | ErrorResponse>
[MessageType.REQUEST_CHALLENGE_RESPONSE]: ProtocolWithReturn<ChallengeRequest, ChallengeResponse | ErrorResponse>
}
}
56 changes: 31 additions & 25 deletions src/background/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,29 +28,29 @@ export interface Session {
}

/**
* Current request tab id
* Popup window id. `-1` means no popup window is open, `-2`
* means popup window is locked (i.e. user is in the middle of a request)
*/
let requestTab: number = -1;
let popupWindowId: number = -1;

/**
* Close current request tab and reset `requestTab` to `-1`
* Close current request tab and reset `popupWindowId` to `-1`
*/
function _closeRequestTab(): void {
function _closePopupWindow(): void {
if (popupWindowId === -1 || popupWindowId === -2) return;

// close popup window if it is open
if (requestTab !== -1) {
PopupPage.close({ id: requestTab });
}
PopupPage.close({ id: popupWindowId });

// reset current request tab
requestTab = -1;

popupWindowId = -1;
}

/**
* Listen for current tab requests from content scripts
* Listen for current tab requests from content scripts (client)
*/
onMessage('close-request-tab', ({ data }) => {
Logger.info('close-request-tab channel', 'close popup message recieved', 'background');
onMessage('close-popup', ({ data }) => {
Logger.info('close-popup channel', 'close popup message recieved', 'background');

if (data) {
// show error message to user
Expand All @@ -59,7 +59,7 @@ onMessage('close-request-tab', ({ data }) => {
}

// close current request tab
_closeRequestTab();
_closePopupWindow();
})

/**
Expand All @@ -82,8 +82,8 @@ onMessage(MessageType.REQUEST_PUBLIC_KEY, async ({ data }) => {
popupPage: await PopupPage.open({ queryString: query })
}

requestTab = session.popupPage.id || 0;
Logger.info('requestTab set to ', requestTab, 'background');
popupWindowId = session.popupPage.id || 0;
Logger.info('popupWindowId set to ', popupWindowId, 'background');

// wait for response from popup window
return new Promise((resolve) => {
Expand Down Expand Up @@ -113,6 +113,9 @@ onMessage(MessageType.REQUEST_PUBLIC_KEY, async ({ data }) => {
key: msg.key
};

// lock popup window to prevent broadcasts from closing the popup window
popupWindowId = -2;

// respond to content script
return resolve(response);
}
Expand All @@ -124,10 +127,10 @@ onMessage(MessageType.REQUEST_PUBLIC_KEY, async ({ data }) => {
* Listen for challenge requests from content scripts and
* responds with a challenge response after user makes a decision (approve/deny)
*/
onMessage(MessageType.REQUEST_SOLUTION, async ({ data }) => {
onMessage(MessageType.REQUEST_CHALLENGE_RESPONSE, async ({ data }) => {
const request: ChallengeRequest = {
origin: data.origin,
type: MessageType.REQUEST_SOLUTION,
type: MessageType.REQUEST_CHALLENGE_RESPONSE,
mode: data.mode,
challenge: data.challenge
};
Expand All @@ -137,16 +140,19 @@ onMessage(MessageType.REQUEST_SOLUTION, async ({ data }) => {

// wait for response from popup window
return new Promise((resolve) => {
// broadcast undefined response, if the messageSession is still active and popup window is closed

// listen for popup window close event
browser.windows.onRemoved.addListener(async (windowId) => {
if (requestTab === windowId) {

// close current popup window if it matches the windowId
if (popupWindowId === windowId) {
const response: ChallengeResponse = {
type: MessageType.RESPONSE_SOLUTION,
solution: null
type: MessageType.RESPONSE_CHALLENGE_RESPONSE,
challengeResponse: null
};

// close current request tab
_closeRequestTab();
_closePopupWindow();

return resolve(response);
}
Expand All @@ -158,10 +164,10 @@ onMessage(MessageType.REQUEST_SOLUTION, async ({ data }) => {
type: msg.type
};

if (message.type === MessageType.RESPONSE_SOLUTION) {
if (message.type === MessageType.RESPONSE_CHALLENGE_RESPONSE) {
const response: ChallengeResponse = {
type: MessageType.RESPONSE_SOLUTION,
solution: msg.solution
type: MessageType.RESPONSE_CHALLENGE_RESPONSE,
challengeResponse: (msg as ChallengeResponse).challengeResponse
};

// respond to content script
Expand Down
10 changes: 5 additions & 5 deletions src/bridge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ The `bridge` component abstracts the complex logic that web applications would n

## usage

```js
```ts
import { Bridge } from 'ssasy-ext-bridge';

// check if the extension is installed
const extensionInstalled = await Bridge.isExtensionInstalled(); // returns true or false
const extensionInstalled: boolean = await Bridge.isExtensionInstalled(); // returns true or false

if(extensionInstalled === true){

const requestMode = 'login'; // or 'registration'
const requestMode: string = 'login'; // or 'registration'

// request the user's public key
const publicKey = await Bridge.requestPublicKey(requestMode); // returns the user's public key
const publicKey: string = await Bridge.requestPublicKey(requestMode); // returns the user's public key

// ... generate a challenge with the user's public key

// initiate challenge-response
const challengeResponse = await Bridge.requestSolution(requestMode, challenge); // returns the challenge response
const challengeResponse: string = await Bridge.requestChallengeResponse(requestMode, challenge); // returns the challenge response

// ... verify the challenge response
}
Expand Down
62 changes: 49 additions & 13 deletions src/bridge/__tests__/bridge.test.ts
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
import { beforeEach, describe, expect, it } from 'vitest'
import { Bridge } from '~/bridge/src/bridge'
import { MessageType } from '~/bridge/src/types'
import type { ChallengeResponse } from '~/bridge/src/types'
import type { PublicKeyResponse, ChallengeResponse } from '~/bridge/src/types'

describe('Bridge', () => {
describe('isExtensionInstalled')
describe('requestPublicKey')

describe.only('requestSolution', () => {
describe('isExtensionInstalled', () => {
it('should return true if extension is installed');
it('should return false if extension is not installed');
})

describe('requestPublicKey', () => {
/**
* Dispatches an event message with a challenge response. Used to simulate
* the message event from the extension.
*/
function _dispatchSuccessResponse() {
const challengeResponse: ChallengeResponse = { type: MessageType.RESPONSE_SOLUTION, solution: 'solution' };
const response: PublicKeyResponse = { type: MessageType.RESPONSE_PUBLIC_KEY, key: 'key' };

window.dispatchEvent(new MessageEvent(
'message',
{ data: challengeResponse }
{ data: response }
));
}

// mock window.addEventListener response for each test in `requestSolution`
// mock window.addEventListener response for each test in `requestChallengeResponse`
beforeEach(() => {
setTimeout(() => {
_dispatchSuccessResponse();
Expand All @@ -33,25 +34,60 @@ describe('Bridge', () => {
let errorThrown = false;

try {
await Bridge.requestSolution(1 as any, 'challengeString');
await Bridge.requestPublicKey(1 as any);
} catch (error) {
errorThrown = true;
}

expect(errorThrown).toBe(true);
expect(errorThrown).to.be.true;
})

})

describe('requestChallengeResponse', () => {

/**
* Dispatches an event message with a challenge response. Used to simulate
* the message event from the extension.
*/
function _dispatchSuccessResponse() {
const response: ChallengeResponse = { type: MessageType.RESPONSE_CHALLENGE_RESPONSE, challengeResponse: 'challenge response' };

window.dispatchEvent(new MessageEvent(
'message',
{ data: response }
));
}

// mock window.addEventListener response for each test in `requestChallengeResponse`
beforeEach(() => {
setTimeout(() => {
_dispatchSuccessResponse();
}, 500);
})

it('should throw error if requestMode is not a string', async () => {
let errorThrown = false;

try {
await Bridge.requestChallengeResponse(1 as any, 'challengeString');
} catch (error) {
errorThrown = true;
}

expect(errorThrown).to.be.true;
})

it('should throw error if challengeString is a string', async () => {
let errorThrown = false;

try {
await Bridge.requestSolution('login', 1 as any);
await Bridge.requestChallengeResponse('login', 1 as any);
}
catch (error) {
errorThrown = true;
}

expect(errorThrown).toBe(true);
expect(errorThrown).to.be.true;
})
})
})
11 changes: 11 additions & 0 deletions src/bridge/docs/changelog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Changelog

> Only notable changes are documented here.
## `0.23.10`

- [breaking] renames `requestSolution()` to `requestChallengeResponse()` to better reflect the purpose of the method.

### migrating from `0.23.9` to `0.23.10`

- replace all instances of `Bridge.requestSolution()` with `Bridge.requestChallengeResponse()`
Loading

0 comments on commit 2d1e6dd

Please sign in to comment.