Skip to content

Commit

Permalink
feat(security): Permissions of the Authenticator can be restricted to…
Browse files Browse the repository at this point in the history
… specific URLs
  • Loading branch information
jan-molak committed Mar 21, 2019
1 parent 54f6d70 commit b1a589f
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 6 deletions.
2 changes: 1 addition & 1 deletion extension/manifest.mustache.json
Expand Up @@ -3,7 +3,7 @@
"description": "{{ description }}",
"version": "{{ version }}",
"manifest_version": 2,
"permissions": [ "<all_urls>", "webRequest", "webRequestBlocking" ],
"permissions": [ {{{ permissions }}}, "webRequest", "webRequestBlocking" ],
"background": {
"scripts": [ "authenticator.js" ]
}
Expand Down
28 changes: 28 additions & 0 deletions spec/Authenticator.spec.ts
Expand Up @@ -31,6 +31,34 @@ describe('Authenticator', () => {
});
});

describe('permissions', () => {

it('applies to all URLs by default', () => {
const data = Authenticator.for('user', 'pass').asBase64();

const zip = new Zip(data, {base64: true, checkCRC32: true});

const manifest = JSON.parse(zip.files['manifest.json']._data);

expect(manifest.permissions).to.contain('<all_urls>');
});

it('allows the developer to restrict the extension to specific URLs', () => {
const data = Authenticator.for('user', 'pass', [ 'http://localhost/' ]).asBase64();

const zip = new Zip(data, {base64: true, checkCRC32: true});

const manifest = JSON.parse(zip.files['manifest.json']._data);

expect(manifest.permissions).to.contain('http://localhost/');
expect(manifest.permissions).to.not.contain('<all_urls>');
});

it('complains when given no permissions', () => {
expect(() => Authenticator.for('user', 'pass', [ ])).to.throw('permissions should have length that is greater than 0');
});
});

describe('when handling errors', () => {

given([
Expand Down
20 changes: 15 additions & 5 deletions src/Authenticator.ts
@@ -1,14 +1,21 @@
import fs = require('fs');
import Mustache = require('mustache');
const Zip = require('node-zip'); // tslint:disable-line:no-var-requires no type definitions available
import readPkg = require('read-pkg');
import { coerce, SemVer } from 'semver';
import { ensure, isGreaterThan, isString, property } from 'tiny-types';
import path = require('upath');

const Zip = require('node-zip'); // tslint:disable-line:no-var-requires no type definitions available
import { coerce, SemVer } from 'semver';
import { ensure, isArray, isGreaterThan, isString, property } from 'tiny-types';

export class Authenticator {
static for(username: string, password: string): Authenticator {
return new Authenticator(username, password);
/**
* @param {string} username
* @param {string} password
* @param {string[]} permissions
* See https://developer.chrome.com/extensions/declare_permissions
*/
static for(username: string, password: string, permissions: string[] = ['<all_urls>']): Authenticator {
return new Authenticator(username, password, permissions);
}

asBase64(): string {
Expand All @@ -18,9 +25,11 @@ export class Authenticator {
private constructor(
private readonly username: string,
private readonly password: string,
private readonly permissions: string[],
) {
ensure('username', username, isString(), property('length', isGreaterThan(0)));
ensure('password', password, isString(), property('length', isGreaterThan(0)));
ensure('permissions', permissions, isArray(), property('length', isGreaterThan(0)));
}

private extension(): NodeZip {
Expand All @@ -32,6 +41,7 @@ export class Authenticator {
contentsOf('../extension/manifest.mustache.json'), {
name,
description,
permissions: this.permissions.map(permission => `"${ permission }"`).join(', '),
version: (coerce(version) as SemVer).version,
},
));
Expand Down

0 comments on commit b1a589f

Please sign in to comment.