Skip to content
This repository has been archived by the owner on Oct 23, 2020. It is now read-only.

Add initial prototype #1

Merged
merged 8 commits into from
Aug 10, 2019
Merged
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
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
root = true

[**.{js,json}]
indent_style = space
indent_size = 2
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
!.eslintrc.js
268 changes: 268 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,268 @@
'use strict';

// This is a modified version of the Node.js core ESLint configuration.

module.exports = {
root: true,
env: {
node: true,
es6: true
},
parser: 'babel-eslint',
parserOptions: { sourceType: 'script' },
rules: {
// ESLint built-in rules
// http://eslint.org/docs/rules
'accessor-pairs': 'error',
'array-callback-return': 'error',
'arrow-parens': ['error', 'always'],
'arrow-spacing': ['error', { before: true, after: true }],
'block-scoped-var': 'error',
'block-spacing': 'error',
'brace-style': ['error', '1tbs', { allowSingleLine: true }],
'capitalized-comments': ['error', 'always', {
line: {
// Ignore all lines that have less characters than 20 and all lines that
// start with something that looks like a variable name or code.
// eslint-disable-next-line max-len
ignorePattern: '.{0,20}$|[a-z]+ ?[0-9A-Z_.(/=:[#-]|std|http|ssh|ftp|(let|var|const) [a-z_A-Z0-9]+ =|[b-z] |[a-z]*[0-9].* ',
ignoreInlineComments: true,
ignoreConsecutiveComments: true
},
block: {
ignorePattern: '.*'
}
}],
'comma-dangle': ['error', 'never'],
'comma-spacing': 'error',
'comma-style': 'error',
'computed-property-spacing': 'error',
'constructor-super': 'error',
'dot-location': ['error', 'property'],
'dot-notation': 'error',
'eol-last': 'error',
'eqeqeq': ['error', 'smart'],
'for-direction': 'error',
'func-call-spacing': 'error',
'func-name-matching': 'error',
'func-style': ['error', 'declaration', { allowArrowFunctions: true }],
'getter-return': 'error',
'indent': ['error', 2, {
ArrayExpression: 'first',
CallExpression: { arguments: 'first' },
FunctionDeclaration: { parameters: 'first' },
FunctionExpression: { parameters: 'first' },
MemberExpression: 'off',
ObjectExpression: 'first',
SwitchCase: 1
}],
'key-spacing': ['error', { mode: 'strict' }],
'keyword-spacing': 'error',
'linebreak-style': ['error', 'unix'],
'max-len': ['error', {
code: 80,
ignorePattern: '^// Flags:',
ignoreRegExpLiterals: true,
ignoreUrls: true,
tabWidth: 2
}],
'new-parens': 'error',
'no-async-promise-executor': 'error',
'no-class-assign': 'error',
'no-confusing-arrow': 'error',
'no-const-assign': 'error',
'no-control-regex': 'error',
'no-debugger': 'error',
'no-delete-var': 'error',
'no-dupe-args': 'error',
'no-dupe-class-members': 'error',
'no-dupe-keys': 'error',
'no-duplicate-case': 'error',
'no-duplicate-imports': 'error',
'no-empty-character-class': 'error',
'no-ex-assign': 'error',
'no-extra-boolean-cast': 'error',
'no-extra-parens': ['error', 'functions'],
'no-extra-semi': 'error',
'no-fallthrough': 'error',
'no-func-assign': 'error',
'no-global-assign': 'error',
'no-invalid-regexp': 'error',
'no-irregular-whitespace': 'error',
'no-lonely-if': 'error',
'no-misleading-character-class': 'error',
'no-mixed-requires': 'error',
'no-mixed-spaces-and-tabs': 'error',
'no-multi-spaces': ['error', { ignoreEOLComments: true }],
'no-multiple-empty-lines': ['error', { max: 2, maxEOF: 0, maxBOF: 0 }],
'no-new-require': 'error',
'no-new-symbol': 'error',
'no-obj-calls': 'error',
'no-octal': 'error',
'no-path-concat': 'error',
'no-proto': 'error',
'no-redeclare': ['error', { 'builtinGlobals': false }],
'no-restricted-modules': ['error', 'sys'],
/* eslint-disable max-len */
'no-restricted-properties': [
'error',
{
object: 'assert',
property: 'deepEqual',
message: 'Use `assert.deepStrictEqual()`.'
},
{
object: 'assert',
property: 'notDeepEqual',
message: 'Use `assert.notDeepStrictEqual()`.'
},
{
object: 'assert',
property: 'equal',
message: 'Use `assert.strictEqual()` rather than `assert.equal()`.'
},
{
object: 'assert',
property: 'notEqual',
message: 'Use `assert.notStrictEqual()` rather than `assert.notEqual()`.'
},
{
property: '__defineGetter__',
message: '__defineGetter__ is deprecated.'
},
{
property: '__defineSetter__',
message: '__defineSetter__ is deprecated.'
}
],
'no-restricted-syntax': [
'error',
{
selector: "CallExpression[callee.property.name='deepStrictEqual'][arguments.2.type='Literal']",
message: 'Do not use a literal for the third argument of assert.deepStrictEqual().'
},
{
selector: "CallExpression[callee.property.name='doesNotThrow']",
message: 'Do not use `assert.doesNotThrow()`. Write the code without the wrapper and add a comment instead.'
},
{
selector: "CallExpression[callee.property.name='doesNotReject']",
message: 'Do not use `assert.doesNotReject()`. Write the code without the wrapper and add a comment instead.'
},
{
selector: "CallExpression[callee.property.name='rejects'][arguments.length<2]",
message: '`assert.rejects()` must be invoked with at least two arguments.'
},
{
selector: "CallExpression[callee.property.name='strictEqual'][arguments.2.type='Literal']",
message: 'Do not use a literal for the third argument of assert.strictEqual().'
},
{
selector: "CallExpression[callee.property.name='throws'][arguments.1.type='Literal']:not([arguments.1.regex])",
message: 'Use an object as second argument of `assert.throws()`.'
},
{
selector: "CallExpression[callee.property.name='throws'][arguments.length<2]",
message: '`assert.throws()` must be invoked with at least two arguments.'
},
{
selector: "CallExpression[callee.name='setTimeout'][arguments.length<2]",
message: '`setTimeout()` must be invoked with at least two arguments.'
},
{
selector: "CallExpression[callee.name='setInterval'][arguments.length<2]",
message: '`setInterval()` must be invoked with at least two arguments.'
},
{
selector: 'ThrowStatement > CallExpression[callee.name=/Error$/]',
message: 'Use `new` keyword when throwing an `Error`.'
},
{
selector: "CallExpression[callee.property.name='notDeepStrictEqual'][arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
message: 'The first argument should be the `actual`, not the `expected` value.'
},
{
selector: "CallExpression[callee.property.name='notStrictEqual'][arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
message: 'The first argument should be the `actual`, not the `expected` value.'
},
{
selector: "CallExpression[callee.property.name='deepStrictEqual'][arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
message: 'The first argument should be the `actual`, not the `expected` value.'
},
{
selector: "CallExpression[callee.property.name='strictEqual'][arguments.0.type='Literal']:not([arguments.1.type='Literal']):not([arguments.1.type='ObjectExpression']):not([arguments.1.type='ArrayExpression']):not([arguments.1.type='UnaryExpression'])",
message: 'The first argument should be the `actual`, not the `expected` value.'
}
],
/* eslint-enable max-len */
'no-return-await': 'error',
'no-self-assign': 'error',
'no-self-compare': 'error',
'no-shadow-restricted-names': 'error',
'no-tabs': 'error',
'no-template-curly-in-string': 'error',
'no-this-before-super': 'error',
'no-throw-literal': 'error',
'no-trailing-spaces': 'error',
'no-undef': ['error', { typeof: true }],
'no-undef-init': 'error',
'no-unexpected-multiline': 'error',
'no-unreachable': 'error',
'no-unsafe-finally': 'error',
'no-unsafe-negation': 'error',
'no-unused-labels': 'error',
'no-unused-vars': ['error', { args: 'none', caughtErrors: 'all' }],
'no-use-before-define': ['error', {
classes: true,
functions: false,
variables: false
}],
'no-useless-call': 'error',
'no-useless-catch': 'error',
'no-useless-concat': 'error',
'no-useless-constructor': 'error',
'no-useless-escape': 'error',
'no-useless-return': 'error',
'no-void': 'error',
'no-whitespace-before-property': 'error',
'no-with': 'error',
'object-curly-spacing': ['error', 'always'],
'one-var': ['error', { initialized: 'never' }],
'one-var-declaration-per-line': 'error',
'operator-linebreak': ['error', 'after'],
'prefer-const': ['error', { ignoreReadBeforeAssign: true }],
'quotes': ['error', 'single', { avoidEscape: true }],
'quote-props': ['error', 'consistent'],
'rest-spread-spacing': 'error',
'semi': 'error',
'semi-spacing': 'error',
'space-before-blocks': ['error', 'always'],
'space-before-function-paren': ['error', {
anonymous: 'never',
named: 'never',
asyncArrow: 'always'
}],
'space-in-parens': ['error', 'never'],
'space-infix-ops': 'error',
'space-unary-ops': 'error',
'spaced-comment': ['error', 'always', {
'block': { 'balanced': true },
'exceptions': ['-']
}],
'strict': ['error', 'global'],
'symbol-description': 'error',
'template-curly-spacing': 'error',
'unicode-bom': 'error',
'use-isnan': 'error',
'valid-typeof': 'error'
},
globals: {
Atomics: 'readable',
BigInt: 'readable',
BigInt64Array: 'readable',
BigUint64Array: 'readable',
TextEncoder: 'readable',
TextDecoder: 'readable',
queueMicrotask: 'readable'
}
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node_modules
7 changes: 7 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
language: node_js
node_js:
- "12"

script:
- npm run lint
- npm test
44 changes: 44 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# WebCrypto Prototype for Node.js

This is a partial and experimental WebCrypto implementation for the Node.js
platform.

## Asynchonicity

The WebCrypto specification requires almost all operations to be completed
asynchronously, however, Node.js implements very few operations asynchronously.
Usually, this is not a problem, since most cryptographic functions are
incredibly fast compared to the overhead that comes with asynchronicity,
and because Node.js implements most cryptographic features through efficient
streaming interfaces. WebCrypto has no streaming interfaces but only one-shot
APIs. Encrypting, hashing, signing or verifying large amounts of data is thus
difficult in WebCrypto without underlying asynchronous APIs.

## Development

### Structure

The main export of this package is implemented in `lib/index.js` and represents
the `Crypto` interface as defined in section 10 of the
[WebCrypto specification][]. It contains two members:

- The `subtle` attribute is implemented in `lib/subtle.js`, including all
methods described in section 14.3 of the WebCrypto specification. These
methods usually delegate work to one or more cryptographic operations
that are listed in section 18.2.2 and implemented in `lib/algorithms/`.
- The `getRandomValues` function is implemented in `lib/random.js`.

### Tests

The `test` directory contains a small number of unit tests. All of these tests
are required to pass after each commit. You can run unit tests using `npm test`.

It is our intention to add Web Platform Tests (WPT) at some point. When this
happens, not all WPTs are required to pass, but if a test passes, it must not be
broken by a later commit.

### Linting

This repository uses ESLint. Use `npm run lint` to check the code.

[WebCrypto specification]: https://www.w3.org/TR/WebCryptoAPI/
Loading