Skip to content

Commit

Permalink
Firefox & Safari support (#163)
Browse files Browse the repository at this point in the history
  • Loading branch information
eligrey authored Oct 31, 2020
1 parent 74a3fdc commit ccc89fe
Show file tree
Hide file tree
Showing 37 changed files with 1,827 additions and 2,286 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ module.exports = {
comments: 200,
},
],
'max-lines': ['error', 350],
'max-lines': ['error', 375],
// "newline-per-chained-call": ["error", { "ignoreChainWithDepth": 2 }],
'no-bitwise': [
'error',
Expand Down
6 changes: 5 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"cSpell.words": [
"Hacky",
"Ponyfill",
"bowser",
"browserstack",
"buffer",
Expand Down Expand Up @@ -69,5 +70,8 @@
"webm",
"zh"
],
"typescript.tsdk": "node_modules/typescript/lib"
"typescript.tsdk": "node_modules/typescript/lib",
"editor.formatOnSave": true,
"prettier.packageManager": "yarn",
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
27 changes: 18 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,19 @@

## Compatibility

| | .decrypt | .encrypt |
| ------- | -------: | -------: |
| Chrome |||
| Safari |||
| Edge |||
| Firefox |||
| | .decrypt | .encrypt | .saveZip |
| -------- | -------: | -------: | -------: |
| Chrome ||||
| Edge >18 ||||
| Safari | 🟡 | 🟡 | 🟡 |
| Firefox | 🟡 | 🟡 | 🟡 |
| Edge 18 ||||

✅ = Full support

🟡 = 32 MiB limit

❌ = No support

## Usage

Expand Down Expand Up @@ -110,7 +117,10 @@ penumbra.encrypt(options: PenumbraEncryptionOptions, ...files: PenumbraFile[]):
size = 4096 * 128;
addEventListener('penumbra-progress', (e) => console.log(e.type, e.detail));
addEventListener('penumbra-complete', (e) => console.log(e.type, e.detail));
file = penumbra.encrypt(null, { stream: new Uint8Array(size), size });
file = penumbra.encrypt(null, {
stream: new Response(new Uint8Array(size)).body,
size,
});
data = [];
file.then(async ([encrypted]) => {
console.log('encryption complete');
Expand All @@ -135,13 +145,12 @@ penumbra.decrypt(options: PenumbraDecryptionInfo, ...files: PenumbraEncryptedFil
```

```ts
const { intoStream } = self;
const te = new TextEncoder();
const td = new TextDecoder();
const data = te.encode('test');
const { byteLength: size } = data;
const [encrypted] = await penumbra.encrypt(null, {
stream: intoStream(data),
stream: data,
size,
});
const options = await penumbra.getDecryptionInfo(encrypted);
Expand Down
5 changes: 1 addition & 4 deletions babel.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,5 @@ module.exports = {
},
],
],
plugins: [
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-object-rest-spread',
],
plugins: ['@babel/plugin-proposal-class-properties'],
};
105 changes: 83 additions & 22 deletions src/demo/demo.js → demo/demo.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
/* eslint-disable max-lines */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
/* eslint-disable max-lines */
const view = self;

const tests = [];
const results = [];
let failures = 0;

/**
Expand Down Expand Up @@ -45,6 +45,12 @@ const onReady = async (
[
'penumbra.get() and penumbra.getTextOrURI() test (no credentials)',
async () => {
if (!self.TextEncoder) {
console.warn(
'skipping test due to lack of browser support for TextEncoder',
);
return false;
}
const cacheBuster = Math.random()
.toString(10)
.slice(2);
Expand All @@ -65,7 +71,7 @@ const onReady = async (
} = await penumbra.getTextOrURI(await penumbra.get(NYT))[0];
const test1Hash = await hash(
'SHA-256',
new TextEncoder().encode(test1Text),
new self.TextEncoder().encode(test1Text),
);
const ref1Hash =
'4933a43366fdda7371f02bb2a7e21b38f23db88a474b9abf9e33309cd15594d5';
Expand Down Expand Up @@ -259,6 +265,50 @@ const onReady = async (
});
},
],
[
'preconnect',
async (t) => {
const measurePreconnects = () =>
document.querySelectorAll('link[rel="preconnect"]').length;
const start = measurePreconnects();
const cleanup = penumbra.preconnect({
url: 'https://s3-us-west-2.amazonaws.com/bencmbrook/NYT.txt.enc',
filePrefix: 'NYT',
mimetype: 'text/plain',
decryptionOptions: {
key: 'vScyqmJKqGl73mJkuwm/zPBQk0wct9eQ5wPE8laGcWM=',
iv: '6lNU+2vxJw6SFgse',
authTag: 'gadZhS1QozjEmfmHLblzbg==',
},
});
const after = measurePreconnects();
cleanup();
t.assert(start < after);
t.end();
},
],
[
'preload',
async (t) => {
const measurePreloads = () =>
document.querySelectorAll('link[rel="preload"]').length;
const start = measurePreloads();
const cleanup = penumbra.preload({
url: 'https://s3-us-west-2.amazonaws.com/bencmbrook/NYT.txt.enc',
filePrefix: 'NYT',
mimetype: 'text/plain',
decryptionOptions: {
key: 'vScyqmJKqGl73mJkuwm/zPBQk0wct9eQ5wPE8laGcWM=',
iv: '6lNU+2vxJw6SFgse',
authTag: 'gadZhS1QozjEmfmHLblzbg==',
},
});
const after = measurePreloads();
cleanup();
t.assert(start < after);
t.end();
},
],
[
'penumbra.getBlob()',
async () => {
Expand All @@ -285,17 +335,18 @@ const onReady = async (
[
'penumbra.encrypt()',
async () => {
if (navigator.userAgent.toLowerCase().includes('firefox')) {
console.error(
'penumbra.encrypt() test skipped for Firefox. TODO: Fix penumbra.encrypt() in Firefox!',
if (!self.TextEncoder || !self.TextDecoder) {
console.warn(
'skipping test due to lack of browser support for TextEncoder/TextDecoder',
);
return true;
return false;
}
const te = new TextEncoder();
const td = new TextDecoder();
const te = new self.TextEncoder();
const td = new self.TextDecoder();
const input = 'test';
const stream = te.encode(input);
const { byteLength: size } = stream;
const buffer = te.encode(input);
const { byteLength: size } = buffer;
const stream = new Response(buffer).body;
const options = null;
const file = {
stream,
Expand All @@ -307,7 +358,9 @@ const onReady = async (
const decryptedData = await new Response(
decrypted.stream,
).arrayBuffer();
return td.decode(decryptedData) === input;
const decryptedText = td.decode(decryptedData);
console.log('decrypted text:', decryptedText);
return decryptedText === input;
},
],
[
Expand All @@ -317,6 +370,8 @@ const onReady = async (
new Promise(async (resolve) => {
const expectedReferenceHashes = [
'318e197f7df584c339ec6d06490eb9cb3cdbb41c218809690d39d70d79dff48f',
'6cbf553053fcfe8b6c5e17313ef4383fcef4bc0cf3df48c904ed5e7b05af04a6',
'7559c3628a54a498b715edbbb9a0f16fc65e94eaaf185b41e91f6bddf1a8e02e',
];
let progressEventFiredAndWorking = false;
let completeEventFired = false;
Expand All @@ -335,6 +390,7 @@ const onReady = async (
allowDuplicates: true,
saveBuffer: true,
});

writer.write(
...(await penumbra.get(
{
Expand Down Expand Up @@ -467,19 +523,24 @@ const onReady = async (
const getTestColor = (passed) => (passed ? 'limegreen' : 'crimson');

// eslint-disable-next-line no-restricted-syntax
for await (const [name, test] of tests) {
const passed = await test();
failures += !passed;
console.log(
`%c${
passed ? '✅ PASS' : '❌ FAIL'
} %c${name} (%creturned ${JSON.stringify(passed)}%c)`,
`font-size:larger;color:${getTestColor(passed)}`,
'',
'color:gray',
'',
for (const [name, test] of tests) {
results.push(
// eslint-disable-next-line no-loop-func
test().then((passed) => {
failures += !passed;
console.log(
`%c${
passed ? '✅ PASS' : '❌ FAIL'
} %c${name} (%creturned ${JSON.stringify(passed)}%c)`,
`font-size:larger;color:${getTestColor(passed)}`,
'',
'color:gray',
'',
);
}),
);
}
await Promise.all(results);
console.log(
`%c${
failures
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion example/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ <h2>The data below is downloaded and decrypted</h2>
<script src="jsAnimation.js"></script>
<script src="files.js"></script>
<script src="displayTable.js"></script>
<script src="./build/penumbra.js" async defer></script>
<script src="penumbra.js" async defer></script>
<script src="index.js"></script>
</body>
</html>
36 changes: 18 additions & 18 deletions karma.browserstack.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,39 +3,39 @@ const { short } = require('git-rev-sync');
const getGlobalConfig = require('./karma.global');

module.exports = (config) => {
// TODO add more browsers. this util is useful:
// https://www.browserstack.com/automate/capabilities
const customLaunchers = {
bs_chrome_pc: {
base: 'BrowserStack',
browser: 'Chrome',
browser_version: '85',
os: 'Windows',
os_version: '10',
device: null,
real_mobile: null,
},
bs_firefox_pc: {
// Skips .encrypt/.saveZip tests
base: 'BrowserStack',
browser: 'Firefox',
browser_version: '80',
os: 'Windows',
os_version: '10',
device: null,
real_mobile: null,
},
bs_safari_mac: {
// Skips .encrypt/.saveZip tests
base: 'BrowserStack',
browser: 'Safari',
browser_version: '13',
os: 'OS X',
os_version: 'Catalina',
},
bs_edge_pc: {
base: 'BrowserStack',
browser: 'Edge',
browser_version: '85',
os: 'Windows',
os_version: '10',
},
/**
* TODO: https://github.com/transcend-io/penumbra/issues/164
* Uncomment this entry once BrowserStack supports Safari 14.
* In the meantime Safari can be tested locally through `yarn start:demo`.
*/
// bs_safari_mac: {
// base: 'BrowserStack',
// browser: 'Safari',
// browser_version: '14',
// os: 'OS X',
// os_version: 'Catalina',
// device: null,
// real_mobile: null,
// },
};

const globalConfig = getGlobalConfig(config);
Expand Down
22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@transcend-io/penumbra",
"version": "4.17.2",
"version": "4.18.0",
"description": "Crypto streams for the browser.",
"main": "build/penumbra.js",
"types": "ts-build/src/index.d.ts",
Expand All @@ -15,11 +15,10 @@
"lint:fix": "eslint . --ext .js,.ts,.tsx,.jsx --fix",
"ts:lint": "tslint --project .",
"####### Start #########": "",
"start": "http-server build -a localhost",
"start:example": "yarn build:example && http-server example",
"start:demo": "http-server build",
"start:example": "yarn build:example && http-server example/build/ -o",
"start:demo": "yarn build:demo && http-server demo/build/ -o",
"####### Testing #######": "",
"test:interactive": "http-server build -a localhost",
"test:interactive": "yarn start:demo",
"test:local": "karma start karma.local.js",
"test:local:rebuild": "yarn && karma start karma.local.js",
"test:browserstack": "karma start karma.browserstack.js",
Expand All @@ -29,10 +28,11 @@
"check:deps:interactive": "npm-check -u",
"####### Build #######": "",
"clean": "rimraf build && rimraf coverage",
"build": "yarn clean && mkdir -p build && webpack --config webpack.prod.js && cp src/demo/* build/ && tsc && yarn build:markdown",
"build": "yarn clean && mkdir -p build && webpack --config webpack.prod.js && tsc && yarn build:markdown",
"build:markdown": "markdown-toc -i --bullets '—' README.md && sed -i -e 's/—/-/g' README.md && rm -f README.md-e",
"build:watch": "tsc --watch",
"build:example": "rimraf example/build && cp -a build example",
"build:example": "rimraf example/build && yarn build && mkdir -p demo/build && cp -a example/. build/ && cp -a build/. example/build/",
"build:demo": "rimraf demo/build && yarn build && mkdir -p demo/build && cp -a demo/. build/ && cp -a build/. demo/build/",
"webpack:watch": "yarn clean && webpack --config webpack.dev.js --watch"
},
"repository": {
Expand All @@ -58,18 +58,19 @@
],
"homepage": "https://github.com/transcend-io/penumbra#readme",
"dependencies": {
"@transcend-io/conflux": "^3.0.6",
"@transcend-io/conflux": "^3.2.0",
"@transcend-io/remote-web-streams": "1.0.5",
"comlink": "^4.2.0",
"core-js": "^3.6.4",
"crypto-browserify": "^3.12.0",
"file-saver": "^2.0.2",
"into-stream": "^5.1.1",
"mime-types": "^2.1.26",
"promise.allsettled": "^1.0.2",
"remote-web-streams": "0.1.0",
"streamsaver": "^2.0.4",
"typedarray-to-buffer": "^3.1.5",
"web-streams-node": "^0.4.0"
"web-streams-node": "^0.4.0",
"web-streams-polyfill": "^3.0.0"
},
"devDependencies": {
"@babel/core": "^7.8.7",
Expand All @@ -85,7 +86,6 @@
"@typescript-eslint/parser": "^2.23.0",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.0.6",
"bowser": "^2.9.0",
"check-deps": "^1.4.1",
"codecov": "^3.6.5",
"eslint": "^6.8.0",
Expand Down
Loading

0 comments on commit ccc89fe

Please sign in to comment.