diff --git a/example/encryptFile.html b/example/encryptFile.html
new file mode 100644
index 00000000..047b2b68
--- /dev/null
+++ b/example/encryptFile.html
@@ -0,0 +1,191 @@
+
+
+
+
+
+
+ Document
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/karma.conf.js b/karma.conf.js
index 2c5ea007..f5a6e60e 100644
--- a/karma.conf.js
+++ b/karma.conf.js
@@ -17,6 +17,9 @@ module.exports = function (config) {
browserNoActivityTimeout: 60 * 1000,
singleRun: true,
reporters: ['spec'],
+ specReporter: {
+ showSpecTiming: true, // print the time elapsed for each spec
+ },
preprocessors: {
'src/**/*.ts': ['rollup'],
},
diff --git a/package-lock.json b/package-lock.json
index e69b9eb2..5265d138 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@virgilsecurity/e3kit",
- "version": "0.3.7",
+ "version": "0.3.9",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -77,9 +77,9 @@
"dev": true
},
"@types/fs-extra": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.0.5.tgz",
- "integrity": "sha512-w7iqhDH9mN8eLClQOYTkhdYUOSpp25eXxfc6VbFOGtzxW34JcvctH2bKjj4jD4++z4R5iO5D+pg48W2e03I65A==",
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-5.1.0.tgz",
+ "integrity": "sha512-AInn5+UBFIK9FK5xc9yP5e3TQSPNNgjHByqYcj9g5elVBnDQcQL7PlO1CIRy2gWlbwK7UPYqi7vRvFA44dCmYQ==",
"dev": true,
"requires": {
"@types/node": "*"
@@ -112,9 +112,9 @@
"dev": true
},
"@types/lodash": {
- "version": "4.14.123",
- "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.123.tgz",
- "integrity": "sha512-pQvPkc4Nltyx7G1Ww45OjVqUsJP4UsZm+GWJpigXgkikZqJgRm4c48g027o6tdgubWHwFRF15iFd+Y4Pmqv6+Q==",
+ "version": "4.14.126",
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.126.tgz",
+ "integrity": "sha512-HxQ+wQnBtnL0LszZrVdMqWIlzZNyKuMLUb6swQ3mo6ysPqpAu7gfnapCQIi0B+Mrf0fNLZh8AWgJs2njejVasg==",
"dev": true
},
"@types/marked": {
@@ -142,15 +142,24 @@
"dev": true
},
"@types/shelljs": {
- "version": "0.8.3",
- "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.3.tgz",
- "integrity": "sha512-miY41hqc5SkRlsZDod3heDa4OS9xv8G77EMBQuSpqq86HBn66l7F+f8y9YKm+1PIuwC8QEZVwN8YxOOG7Y67fA==",
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/@types/shelljs/-/shelljs-0.8.5.tgz",
+ "integrity": "sha512-bZgjwIWu9gHCjirKJoOlLzGi5N0QgZ5t7EXEuoqyWCHTuSddURXo3FOBYDyRPNOWzZ6NbkLvZnVkn483Y/tvcQ==",
"dev": true,
"requires": {
"@types/glob": "*",
"@types/node": "*"
}
},
+ "@types/uuid": {
+ "version": "3.4.4",
+ "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
+ "integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==",
+ "dev": true,
+ "requires": {
+ "@types/node": "*"
+ }
+ },
"@virgilsecurity/keyknox": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@virgilsecurity/keyknox/-/keyknox-0.2.4.tgz",
@@ -165,6 +174,15 @@
"integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==",
"dev": true
},
+ "abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "dev": true,
+ "requires": {
+ "event-target-shim": "^5.0.0"
+ }
+ },
"accepts": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz",
@@ -557,6 +575,15 @@
"sprintf-js": "~1.0.2"
}
},
+ "arr-diff": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+ "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+ "dev": true,
+ "requires": {
+ "arr-flatten": "^1.0.1"
+ }
+ },
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
@@ -575,6 +602,30 @@
"integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=",
"dev": true
},
+ "array-filter": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+ "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw=",
+ "dev": true
+ },
+ "array-map": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+ "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI=",
+ "dev": true
+ },
+ "array-reduce": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+ "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys=",
+ "dev": true
+ },
+ "array-unique": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+ "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
+ "dev": true
+ },
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
@@ -703,6 +754,16 @@
}
}
},
+ "babel-runtime": {
+ "version": "6.26.0",
+ "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+ "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+ "dev": true,
+ "requires": {
+ "core-js": "^2.4.0",
+ "regenerator-runtime": "^0.11.0"
+ }
+ },
"backo2": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz",
@@ -867,6 +928,17 @@
"concat-map": "0.0.1"
}
},
+ "braces": {
+ "version": "1.8.5",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+ "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+ "dev": true,
+ "requires": {
+ "expand-range": "^1.8.1",
+ "preserve": "^0.2.0",
+ "repeat-element": "^1.1.2"
+ }
+ },
"browser-process-hrtime": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
@@ -1350,6 +1422,74 @@
}
}
},
+ "cp-file": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/cp-file/-/cp-file-7.0.0.tgz",
+ "integrity": "sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw==",
+ "requires": {
+ "graceful-fs": "^4.1.2",
+ "make-dir": "^3.0.0",
+ "nested-error-stacks": "^2.0.0",
+ "p-event": "^4.1.0"
+ }
+ },
+ "cpx": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/cpx/-/cpx-1.5.0.tgz",
+ "integrity": "sha1-GFvgGFEdhycN7czCkxceN2VauI8=",
+ "dev": true,
+ "requires": {
+ "babel-runtime": "^6.9.2",
+ "chokidar": "^1.6.0",
+ "duplexer": "^0.1.1",
+ "glob": "^7.0.5",
+ "glob2base": "^0.0.12",
+ "minimatch": "^3.0.2",
+ "mkdirp": "^0.5.1",
+ "resolve": "^1.1.7",
+ "safe-buffer": "^5.0.1",
+ "shell-quote": "^1.6.1",
+ "subarg": "^1.0.0"
+ },
+ "dependencies": {
+ "anymatch": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+ "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+ "dev": true,
+ "requires": {
+ "micromatch": "^2.1.5",
+ "normalize-path": "^2.0.0"
+ }
+ },
+ "chokidar": {
+ "version": "1.7.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+ "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+ "dev": true,
+ "requires": {
+ "anymatch": "^1.3.0",
+ "async-each": "^1.0.0",
+ "fsevents": "^1.0.0",
+ "glob-parent": "^2.0.0",
+ "inherits": "^2.0.1",
+ "is-binary-path": "^1.0.0",
+ "is-glob": "^2.0.0",
+ "path-is-absolute": "^1.0.0",
+ "readdirp": "^2.0.0"
+ }
+ },
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
"cross-env": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz",
@@ -1642,6 +1782,12 @@
"integrity": "sha1-mFO2ypgpKst97GepUBj6QLzP9Cw=",
"dev": true
},
+ "duplexer": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz",
+ "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=",
+ "dev": true
+ },
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
@@ -1845,6 +1991,12 @@
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
+ "event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "dev": true
+ },
"eventemitter3": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
@@ -1857,6 +2009,24 @@
"integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
"dev": true
},
+ "expand-brackets": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+ "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+ "dev": true,
+ "requires": {
+ "is-posix-bracket": "^0.1.0"
+ }
+ },
+ "expand-range": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+ "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+ "dev": true,
+ "requires": {
+ "fill-range": "^2.1.0"
+ }
+ },
"expect": {
"version": "24.0.0",
"resolved": "https://registry.npmjs.org/expect/-/expect-24.0.0.tgz",
@@ -2300,6 +2470,15 @@
}
}
},
+ "extglob": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+ "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
@@ -2363,6 +2542,25 @@
"object-assign": "^4.1.0"
}
},
+ "filename-regex": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+ "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
+ "dev": true
+ },
+ "fill-range": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
+ "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
+ "dev": true,
+ "requires": {
+ "is-number": "^2.1.0",
+ "isobject": "^2.0.0",
+ "randomatic": "^3.0.0",
+ "repeat-element": "^1.1.2",
+ "repeat-string": "^1.5.2"
+ }
+ },
"finalhandler": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz",
@@ -2395,6 +2593,12 @@
}
}
},
+ "find-index": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz",
+ "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=",
+ "dev": true
+ },
"find-parent-dir": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/find-parent-dir/-/find-parent-dir-0.3.0.tgz",
@@ -2421,6 +2625,15 @@
"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
"dev": true
},
+ "for-own": {
+ "version": "0.1.5",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+ "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+ "dev": true,
+ "requires": {
+ "for-in": "^1.0.1"
+ }
+ },
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
@@ -2921,11 +3134,38 @@
"path-is-absolute": "^1.0.0"
}
},
+ "glob-base": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+ "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+ "dev": true,
+ "requires": {
+ "glob-parent": "^2.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
+ "glob-parent": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+ "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+ "dev": true,
+ "requires": {
+ "is-glob": "^2.0.0"
+ }
+ },
+ "glob2base": {
+ "version": "0.0.12",
+ "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz",
+ "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=",
+ "dev": true,
+ "requires": {
+ "find-index": "^0.1.1"
+ }
+ },
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
- "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
- "dev": true
+ "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
},
"growl": {
"version": "1.10.5",
@@ -2934,9 +3174,9 @@
"dev": true
},
"handlebars": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.1.tgz",
- "integrity": "sha512-3Zhi6C0euYZL5sM0Zcy7lInLXKQ+YLcF/olbN010mzGQ4XVm50JeyBnMqofHh696GrciGruC7kCcApPDJvVgwA==",
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.1.2.tgz",
+ "integrity": "sha512-nvfrjqvt9xQ8Z/w0ijewdD/vvWDTOweBUm96NTr66Wfvo1mJenBLwcYmPs3TIBP5ruzYGD7Hx/DaM9RmhroGPw==",
"dev": true,
"requires": {
"neo-async": "^2.6.0",
@@ -3259,12 +3499,33 @@
"integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=",
"dev": true
},
+ "is-dotfile": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+ "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
+ "dev": true
+ },
+ "is-equal-shallow": {
+ "version": "0.1.3",
+ "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+ "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+ "dev": true,
+ "requires": {
+ "is-primitive": "^2.0.0"
+ }
+ },
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"dev": true
},
+ "is-extglob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+ "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
+ "dev": true
+ },
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
@@ -3274,12 +3535,30 @@
"number-is-nan": "^1.0.0"
}
},
+ "is-glob": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+ "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+ "dev": true,
+ "requires": {
+ "is-extglob": "^1.0.0"
+ }
+ },
"is-module": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
"integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
"dev": true
},
+ "is-number": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+ "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+ "dev": true,
+ "requires": {
+ "kind-of": "^3.0.2"
+ }
+ },
"is-obj": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
@@ -3312,6 +3591,18 @@
}
}
},
+ "is-posix-bracket": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+ "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
+ "dev": true
+ },
+ "is-primitive": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+ "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
+ "dev": true
+ },
"is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
@@ -3369,6 +3660,15 @@
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
"dev": true
},
+ "isobject": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+ "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+ "dev": true,
+ "requires": {
+ "isarray": "1.0.0"
+ }
+ },
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
@@ -3406,9 +3706,9 @@
"dev": true
},
"js-yaml": {
- "version": "3.12.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz",
- "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=",
+ "version": "3.13.1",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
+ "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
@@ -3499,6 +3799,12 @@
"graceful-fs": "^4.1.6"
}
},
+ "jsonify": {
+ "version": "0.0.0",
+ "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+ "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
+ "dev": true
+ },
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
@@ -4261,6 +4567,21 @@
"sourcemap-codec": "^1.4.1"
}
},
+ "make-dir": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.0.0.tgz",
+ "integrity": "sha512-grNJDhb8b1Jm1qeqW5R/O63wUo4UXo2v2HMic6YT9i/HBlF93S8jkMgH7yugvY9ABDShH4VZMn8I+U8+fCNegw==",
+ "requires": {
+ "semver": "^6.0.0"
+ },
+ "dependencies": {
+ "semver": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.0.0.tgz",
+ "integrity": "sha512-0UewU+9rFapKFnlbirLi3byoOuhrSsli/z/ihNnvM24vgF+8sNBiI1LZPBSH9wJKUwaUbw+s3hToDLCXkrghrQ=="
+ }
+ }
+ },
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
@@ -4282,12 +4603,50 @@
"integrity": "sha512-tMsdNBgOsrUophCAFQl0XPe6Zqk/uy9gnue+jIIKhykO51hxyu6uNx7zBPy0+y/WKYVZZMspV9YeXLNdKk+iYw==",
"dev": true
},
+ "math-random": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
+ "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
+ "dev": true
+ },
"media-typer": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
+ "micromatch": {
+ "version": "2.3.11",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+ "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+ "dev": true,
+ "requires": {
+ "arr-diff": "^2.0.0",
+ "array-unique": "^0.2.1",
+ "braces": "^1.8.2",
+ "expand-brackets": "^0.1.4",
+ "extglob": "^0.3.1",
+ "filename-regex": "^2.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.1",
+ "kind-of": "^3.0.2",
+ "normalize-path": "^2.0.1",
+ "object.omit": "^2.0.0",
+ "parse-glob": "^3.0.4",
+ "regex-cache": "^0.4.2"
+ },
+ "dependencies": {
+ "normalize-path": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+ "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+ "dev": true,
+ "requires": {
+ "remove-trailing-separator": "^1.0.1"
+ }
+ }
+ }
+ },
"mime": {
"version": "2.4.0",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.0.tgz",
@@ -4483,11 +4842,16 @@
"dev": true
},
"neo-async": {
- "version": "2.6.0",
- "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.0.tgz",
- "integrity": "sha512-MFh0d/Wa7vkKO3Y3LlacqAEeHK0mckVqzDieUKTT+KGxi+zIpeVsFxymkIiRpbpDziHc290Xr9A1O4Om7otoRA==",
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz",
+ "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==",
"dev": true
},
+ "nested-error-stacks": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-2.1.0.tgz",
+ "integrity": "sha512-AO81vsIO1k1sM4Zrd6Hu7regmJN1NSiAja10gc4bX3F0wd+9rQmcuHQaHVQCYIEC8iFXnE+mavh23GOt7wBgug=="
+ },
"next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
@@ -4615,6 +4979,16 @@
}
}
},
+ "object.omit": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+ "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+ "dev": true,
+ "requires": {
+ "for-own": "^0.1.4",
+ "is-extendable": "^0.1.1"
+ }
+ },
"object.pick": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
@@ -4720,11 +5094,18 @@
"os-tmpdir": "^1.0.0"
}
},
+ "p-event": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz",
+ "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==",
+ "requires": {
+ "p-timeout": "^2.0.1"
+ }
+ },
"p-finally": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
- "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
- "dev": true
+ "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
},
"p-map": {
"version": "1.2.0",
@@ -4732,6 +5113,26 @@
"integrity": "sha1-5OlPMR6rvIYzoeeZCBZfyiYkG2s=",
"dev": true
},
+ "p-timeout": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz",
+ "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==",
+ "requires": {
+ "p-finally": "^1.0.0"
+ }
+ },
+ "parse-glob": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+ "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+ "dev": true,
+ "requires": {
+ "glob-base": "^0.3.0",
+ "is-dotfile": "^1.0.0",
+ "is-extglob": "^1.0.0",
+ "is-glob": "^2.0.0"
+ }
+ },
"parse5": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz",
@@ -4835,6 +5236,12 @@
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
+ "preserve": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+ "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
+ "dev": true
+ },
"prettier": {
"version": "1.14.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.14.3.tgz",
@@ -4907,6 +5314,31 @@
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==",
"dev": true
},
+ "randomatic": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
+ "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
+ "dev": true,
+ "requires": {
+ "is-number": "^4.0.0",
+ "kind-of": "^6.0.0",
+ "math-random": "^1.0.1"
+ },
+ "dependencies": {
+ "is-number": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
+ "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
+ "dev": true
+ },
+ "kind-of": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
+ "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
+ "dev": true
+ }
+ }
+ },
"range-parser": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
@@ -5273,6 +5705,21 @@
"integrity": "sha1-MRvwxrY814LyKKgavhRqK/qcVvI=",
"dev": true
},
+ "regenerator-runtime": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+ "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+ "dev": true
+ },
+ "regex-cache": {
+ "version": "0.4.4",
+ "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+ "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+ "dev": true,
+ "requires": {
+ "is-equal-shallow": "^0.1.3"
+ }
+ },
"regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
@@ -5955,6 +6402,18 @@
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
"dev": true
},
+ "shell-quote": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+ "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+ "dev": true,
+ "requires": {
+ "array-filter": "~0.0.0",
+ "array-map": "~0.0.0",
+ "array-reduce": "~0.0.0",
+ "jsonify": "~0.0.0"
+ }
+ },
"shelljs": {
"version": "0.8.3",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
@@ -6357,6 +6816,23 @@
"dev": true,
"optional": true
},
+ "subarg": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+ "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+ "dev": true,
+ "requires": {
+ "minimist": "^1.1.0"
+ },
+ "dependencies": {
+ "minimist": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+ "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
+ "dev": true
+ }
+ }
+ },
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
@@ -6931,9 +7407,9 @@
}
},
"virgil-crypto": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/virgil-crypto/-/virgil-crypto-3.2.2.tgz",
- "integrity": "sha512-9M8Ar95M9B/hBwRQwOqj3hur59aXiuMb3GASZulUwxB9Oit25IzIMrdIZ8qYbFP3Neuld7UR2ebq+J299JfSjw==",
+ "version": "3.2.3",
+ "resolved": "https://registry.npmjs.org/virgil-crypto/-/virgil-crypto-3.2.3.tgz",
+ "integrity": "sha512-S+Qo39isymVE2DbKDJNZZu4ENQa/niWNwtA0kDfn6+EoFRDzUL9A1QxwR3pTNoWwzcJqJujR2/hKQZSezANCwA==",
"requires": {
"node-fetch": "^2.1.2",
"readable-stream": "^3.0.6",
diff --git a/package.json b/package.json
index f0b48b9c..aed69f3f 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@virgilsecurity/e3kit",
- "version": "0.3.9",
+ "version": "0.4.0",
"description": "End-to-end encryption with multiple device support powered by Virgil Security",
"main": "./dist/e3kit.browser.es.js",
"module": "./dist/e3kit.browser.es.js",
@@ -22,7 +22,8 @@
"prettier": "prettier 'src/**/*.ts' --write",
"precommit": "lint-staged",
"test": "karma start",
- "docs": "typedoc src"
+ "docs": "typedoc src && npm run build:browser:umd && npm run encryptFileDoc",
+ "encryptFileDoc": "cpx example/encryptFile.html docs && cpx dist/e3kit.browser.umd.min.js docs"
},
"lint-staged": {
"src/**/*.ts": [
@@ -32,13 +33,16 @@
},
"dependencies": {
"@virgilsecurity/keyknox": "^0.2.4",
- "virgil-crypto": "^3.2.2",
+ "virgil-crypto": "^3.2.3",
"virgil-pythia": "^0.2.3",
"virgil-sdk": "^5.2.2"
},
"peerDependencies": {},
"devDependencies": {
"@types/mocha": "^5.2.5",
+ "@types/uuid": "^3.4.4",
+ "abort-controller": "^3.0.0",
+ "cpx": "^1.5.0",
"cross-env": "^5.2.0",
"dotenv": "^6.0.0",
"es6-symbol": "^3.1.1",
@@ -70,7 +74,8 @@
"tslint-plugin-prettier": "^1.3.0",
"typedoc": "^0.14.2",
"typedoc-plugin-markdown": "^1.1.27",
- "typescript": "^3.0.1"
+ "typescript": "^3.0.1",
+ "uuid": "^3.3.2"
},
"sideEffects": false
}
diff --git a/src/EThree.ts b/src/EThree.ts
index d4a7bb40..d0a43498 100644
--- a/src/EThree.ts
+++ b/src/EThree.ts
@@ -24,51 +24,32 @@ import {
LookupError,
DUPLICATE_IDENTITIES,
EMPTY_ARRAY,
+ throwIllegalInvocationError,
+ IntegrityCheckFailedError,
} from './errors';
-import { isArray, isString, isVirgilPublicKey } from './utils/typeguards';
-import { hasDuplicates, getObjectValues } from './utils/array';
+import { isArray, isString, isFile, isVirgilPublicKey } from './utils/typeguards';
import { withDefaults } from './utils/object';
-
-export interface IEThreeInitOptions {
- /**
- * Implementation of IKeyEntryStorage. Used IndexedDB Key Storage from
- * [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript) by default.
- */
- keyEntryStorage?: IKeyEntryStorage;
- /**
- * Url of the Card Services. Used for development purposes.
- */
- apiUrl?: string;
-}
-/**
- * @hidden
- */
-export interface IEThreeCtorOptions extends IEThreeInitOptions {
- /**
- * Implementation of IAccessTokenProvider from [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript);
- */
- accessTokenProvider: IAccessTokenProvider;
-}
-
-type KeyPair = {
- privateKey: VirgilPrivateKey;
- publicKey: VirgilPublicKey;
-};
-
-export type LookupResult = {
- [identity: string]: VirgilPublicKey;
-};
-
-const throwIllegalInvocationError = (method: string) => {
- throw new Error(`Calling ${method} two or more times in a row is not allowed.`);
-};
-
-type EncryptVirgilPublicKeyArg = LookupResult | VirgilPublicKey;
+import { getObjectValues, hasDuplicates } from './utils/array';
+import { processFile, onChunkCallback } from './utils/processFile';
+import {
+ VIRGIL_STREAM_SIGNING_STATE,
+ VIRGIL_STREAM_ENCRYPTING_STATE,
+ VIRGIL_STREAM_DECRYPTING_STATE,
+ VIRGIL_STREAM_VERIFYING_STATE,
+ DEFAULT_API_URL,
+ STORAGE_NAME,
+} from './utils/constants';
+import {
+ EncryptVirgilPublicKeyArg,
+ LookupResult,
+ EThreeInitializeOptions,
+ EncryptFileOptions,
+ DecryptFileOptions,
+} from './types';
+import { KeyPair, EThreeCtorOptions } from './utils/innerTypes';
const _inProcess = Symbol('inProcess');
const _keyLoader = Symbol('keyLoader');
-const STORAGE_NAME = '.virgil-local-storage';
-const DEFAULT_API_URL = 'https://api.virgilsecurity.com';
export default class EThree {
/**
@@ -109,9 +90,9 @@ export default class EThree {
*/
static async initialize(
getToken: () => Promise,
- options: IEThreeInitOptions = {},
+ options: EThreeInitializeOptions = {},
): Promise {
- const opts = withDefaults(options as IEThreeCtorOptions, {
+ const opts = withDefaults(options as EThreeCtorOptions, {
accessTokenProvider: new CachingJwtProvider(getToken),
});
const token = await opts.accessTokenProvider.getToken({ operation: 'get' });
@@ -123,7 +104,7 @@ export default class EThree {
* @hidden
* @param identity - Identity of the current user.
*/
- constructor(identity: string, options: IEThreeCtorOptions) {
+ constructor(identity: string, options: EThreeCtorOptions) {
const opts = withDefaults(options, { apiUrl: DEFAULT_API_URL });
this.identity = identity;
this.accessTokenProvider = opts.accessTokenProvider;
@@ -228,8 +209,8 @@ export default class EThree {
}
/**
- * Encrypts data for recipient(s) public key(s). If there is no recipient and message encrypted
- * for the current user, omit public key.
+ * Encrypts and signs data for recipient public key or `LookupResult` dictionary for multiple recipients.
+ * If there is no recipient and message encrypted for the current user, omit public key.
*/
async encrypt(
message: ArrayBuffer,
@@ -239,22 +220,13 @@ export default class EThree {
async encrypt(message: Buffer, publicKey?: EncryptVirgilPublicKeyArg): Promise;
async encrypt(message: Data, publicKeys?: EncryptVirgilPublicKeyArg): Promise {
const isMessageString = isString(message);
- let argument: VirgilPublicKey[];
-
- if (publicKeys == null) argument = [];
- else if (isVirgilPublicKey(publicKeys)) argument = [publicKeys];
- else argument = getObjectValues(publicKeys) as VirgilPublicKey[];
const privateKey = await this[_keyLoader].loadLocalPrivateKey();
if (!privateKey) throw new RegisterRequiredError();
- const ownPublicKey = this.virgilCrypto.extractPublicKey(privateKey);
-
- if (!this._isOwnPublicKeysIncluded(ownPublicKey, argument)) {
- argument.push(ownPublicKey);
- }
+ const publicKeysArray = this._addOwnPublicKey(privateKey, publicKeys);
- const res: Data = this.virgilCrypto.signThenEncrypt(message, privateKey, argument);
+ const res: Data = this.virgilCrypto.signThenEncrypt(message, privateKey, publicKeysArray);
if (isMessageString) return res.toString('base64');
return res;
}
@@ -278,6 +250,210 @@ export default class EThree {
return res as Buffer;
}
+ /**
+ * Signs and encrypts File or Blob for recipient public key or `LookupResult` dictionary for multiple
+ * recipients. If there is no recipient and the message is encrypted for the current user, omit the
+ * public key parameter. You can define chunk size and a callback, that will be invoked on each chunk.
+ *
+ * The file will be read twice during this method execution:
+ * 1. To calculate the signature of the plaintext file.
+ * 2. To encrypt the file with encoded signature.
+ */
+ async encryptFile(
+ file: File | Blob,
+ publicKeys?: EncryptVirgilPublicKeyArg,
+ options: EncryptFileOptions = {},
+ ): Promise {
+ const chunkSize = options.chunkSize ? options.chunkSize : 64 * 1024;
+ if (!Number.isInteger(chunkSize)) throw TypeError('chunkSize should be an integer value');
+ const fileSize = file.size;
+
+ const privateKey = await this[_keyLoader].loadLocalPrivateKey();
+ if (!privateKey) throw new RegisterRequiredError();
+
+ const publicKeysArray = this._addOwnPublicKey(privateKey, publicKeys);
+
+ const streamSigner = this.virgilCrypto.createStreamSigner();
+
+ const signaturePromise = new Promise((resolve, reject) => {
+ const onChunkCallback: onChunkCallback = (chunk, offset) => {
+ if (options.onProgress) {
+ options.onProgress({
+ state: VIRGIL_STREAM_SIGNING_STATE,
+ bytesProcessed: offset,
+ fileSize: fileSize,
+ });
+ }
+ streamSigner.update(chunk);
+ };
+
+ const onFinishCallback = () => resolve(streamSigner.sign(privateKey));
+
+ const onErrorCallback = (err: any) => {
+ streamSigner.dispose();
+ reject(err);
+ };
+
+ processFile({
+ file,
+ chunkSize,
+ onChunkCallback,
+ onFinishCallback,
+ onErrorCallback,
+ signal: options.signal,
+ });
+ });
+
+ const streamCipher = this.virgilCrypto.createStreamCipher(publicKeysArray, {
+ signature: await signaturePromise,
+ });
+
+ const encryptedChunksPromise = new Promise((resolve, reject) => {
+ const encryptedChunks: Buffer[] = [];
+ encryptedChunks.push(streamCipher.start());
+
+ const onChunkCallback: onChunkCallback = (chunk, offset) => {
+ encryptedChunks.push(streamCipher.update(chunk));
+ if (options.onProgress) {
+ options.onProgress({
+ state: VIRGIL_STREAM_ENCRYPTING_STATE,
+ bytesProcessed: offset,
+ fileSize: fileSize,
+ });
+ }
+ };
+
+ const onFinishCallback = () => {
+ encryptedChunks.push(streamCipher.final());
+ resolve(encryptedChunks);
+ };
+
+ const onErrorCallback = (err: any) => {
+ reject(err);
+ streamCipher.dispose();
+ };
+
+ processFile({
+ file,
+ chunkSize,
+ onChunkCallback,
+ onFinishCallback,
+ onErrorCallback,
+ signal: options.signal,
+ });
+ });
+
+ const encryptedChunks = await encryptedChunksPromise;
+ if (isFile(file)) return new File(encryptedChunks, file.name, { type: file.type });
+ return new Blob(encryptedChunks, { type: file.type });
+ }
+ /**
+ * Decrypts and verifies integrity of File or Blob for recipient public key. If there is no recipient
+ * and the message is encrypted for the current user, omit the public key parameter. You can define
+ * chunk size and a callback, that will be invoked on each chunk.
+ *
+ * The file will be read twice during this method execution:
+ * 1. To decrypt encrypted file.
+ * 2. To verify the validity of the signature over the decrypted file for the public key.
+ */
+ async decryptFile(
+ file: File | Blob,
+ publicKey?: VirgilPublicKey,
+ options: DecryptFileOptions = {},
+ ): Promise {
+ const fileSize = file.size;
+ const chunkSize = options.chunkSize ? options.chunkSize : 64 * 1024;
+ if (!Number.isInteger(chunkSize)) throw TypeError('chunkSize should be an integer value');
+
+ const privateKey = await this[_keyLoader].loadLocalPrivateKey();
+ if (!privateKey) throw new RegisterRequiredError();
+ if (!publicKey) publicKey = this.virgilCrypto.extractPublicKey(privateKey);
+
+ const streamDecipher = this.virgilCrypto.createStreamDecipher(privateKey);
+
+ type decryptStreamResult = { signature: Buffer; decryptedChunks: Buffer[] };
+ const decryptedChunksPromise = new Promise((resolve, reject) => {
+ const decryptedChunks: Buffer[] = [];
+
+ const onChunkCallback: onChunkCallback = (chunk, offset) => {
+ decryptedChunks.push(streamDecipher.update(chunk));
+ if (options.onProgress) {
+ options.onProgress({
+ state: VIRGIL_STREAM_DECRYPTING_STATE,
+ bytesProcessed: offset,
+ fileSize: fileSize,
+ });
+ }
+ };
+
+ const onFinishCallback = () => {
+ decryptedChunks.push(streamDecipher.final(false));
+ const signature = streamDecipher.getSignature();
+ streamDecipher.dispose();
+ if (!signature) throw new IntegrityCheckFailedError('Signature not present.');
+ resolve({ decryptedChunks, signature });
+ };
+
+ const onErrorCallback = (err: any) => {
+ streamDecipher.dispose();
+ reject(err);
+ };
+
+ processFile({
+ file,
+ chunkSize,
+ onChunkCallback,
+ onFinishCallback,
+ onErrorCallback,
+ signal: options.signal,
+ });
+ });
+
+ const { decryptedChunks, signature } = await decryptedChunksPromise;
+ const streamVerifier = this.virgilCrypto.createStreamVerifier(signature, 'utf8');
+
+ let decryptedFile: File | Blob;
+ if (isFile(file)) decryptedFile = new File(decryptedChunks, file.name, { type: file.type });
+ decryptedFile = new Blob(decryptedChunks, { type: file.type });
+ const decryptedFileSize = decryptedFile.size;
+
+ const verifyPromise = new Promise((resolve, reject) => {
+ const onChunkCallback: onChunkCallback = (chunk, offset) => {
+ streamVerifier.update(chunk);
+ if (options.onProgress) {
+ options.onProgress({
+ state: VIRGIL_STREAM_VERIFYING_STATE,
+ bytesProcessed: offset,
+ fileSize: decryptedFileSize,
+ });
+ }
+ };
+
+ const onFinishCallback = () => resolve(streamVerifier.verify(publicKey!));
+ const onErrorCallback = (err: any) => {
+ streamVerifier.dispose();
+ reject(err);
+ };
+
+ processFile({
+ file: decryptedFile,
+ chunkSize,
+ onChunkCallback,
+ onFinishCallback,
+ onErrorCallback,
+ signal: options.signal,
+ });
+ });
+
+ const isVerified = await verifyPromise;
+
+ if (!isVerified) {
+ throw new IntegrityCheckFailedError('Signature verification has failed.');
+ }
+
+ return decryptedFile;
+ }
+
/**
* Find public keys for user identities registered on Virgil Cloud.
*/
@@ -357,4 +533,19 @@ export default class EThree {
);
return stringKeys.some((key, i) => key === selfPublicKey);
}
+
+ private _addOwnPublicKey(privateKey: VirgilPrivateKey, publicKeys?: EncryptVirgilPublicKeyArg) {
+ let argument: VirgilPublicKey[];
+
+ if (publicKeys == null) argument = [];
+ else if (isVirgilPublicKey(publicKeys)) argument = [publicKeys];
+ else argument = getObjectValues(publicKeys) as VirgilPublicKey[];
+
+ const ownPublicKey = this.virgilCrypto.extractPublicKey(privateKey);
+
+ if (!this._isOwnPublicKeysIncluded(ownPublicKey, argument)) {
+ argument.push(ownPublicKey);
+ }
+ return argument;
+ }
}
diff --git a/src/__tests__/EThree.test.ts b/src/__tests__/EThree.test.ts
index b60cbeea..8fad75a7 100644
--- a/src/__tests__/EThree.test.ts
+++ b/src/__tests__/EThree.test.ts
@@ -1,3 +1,4 @@
+import { LookupResult, onEncryptProgressSnapshot, onDecryptProgressSnapshot } from './../types';
import {
RegisterRequiredError,
LookupNotFoundError,
@@ -8,6 +9,7 @@ import {
DUPLICATE_IDENTITIES,
PrivateKeyNoBackupError,
EMPTY_ARRAY,
+ IntegrityCheckFailedError,
} from '../errors';
import {
generator,
@@ -18,10 +20,21 @@ import {
createFetchToken,
virgilCrypto,
initializeEThree,
+ initializeETheeFromIdentity,
+ readFile,
} from './utils.test';
import { IKeyEntry } from 'virgil-sdk';
import { getObjectValues } from '../utils/array';
import expect from 'expect';
+import uuid from 'uuid/v4';
+import { EThree } from '..';
+import {
+ VIRGIL_STREAM_SIGNING_STATE,
+ VIRGIL_STREAM_ENCRYPTING_STATE,
+ VIRGIL_STREAM_DECRYPTING_STATE,
+ VIRGIL_STREAM_VERIFYING_STATE,
+} from '../utils/constants';
+import 'abort-controller/polyfill';
describe('EThree.register()', () => {
before(clear);
@@ -591,3 +604,181 @@ describe('hasPrivateKey()', () => {
return;
});
});
+
+describe('EThree.encryptFile/EThree.decryptFile', async () => {
+ const identity1 = uuid();
+ const identity2 = uuid();
+ const identity3 = uuid();
+
+ let sdk1: EThree, sdk2: EThree, sdk3: EThree, lookupResult: LookupResult;
+
+ const originString = 'foo'.repeat(1024 * 3);
+
+ const originFile = new File([originString], 'foo.txt', {
+ type: 'text/plain',
+ });
+
+ before(async () => {
+ [sdk1, sdk2, sdk3] = await Promise.all([
+ initializeETheeFromIdentity(identity1),
+ initializeETheeFromIdentity(identity2),
+ initializeETheeFromIdentity(identity3),
+ ]);
+
+ await Promise.all([sdk1.register(), sdk2.register(), sdk3.register()]);
+ lookupResult = await sdk1.lookupPublicKeys([identity1, identity2, identity3]);
+ });
+
+ it('should decrypt file for one public key', async () => {
+ const [publicKey2, publicKey1] = await Promise.all([
+ sdk1.lookupPublicKeys(identity2),
+ sdk2.lookupPublicKeys(identity1),
+ ]);
+
+ const encryptedFile = await sdk1.encryptFile(originFile, publicKey2);
+ const decryptedFile = await sdk2.decryptFile(encryptedFile, publicKey1);
+
+ const decryptedString = await readFile(decryptedFile);
+
+ expect(originString).toEqual(decryptedString);
+ });
+
+ it('should encrypt for multiple keys', async () => {
+ const onlyTwoKeys = await sdk1.lookupPublicKeys([identity1, identity2]);
+ const encryptedFile = await sdk1.encryptFile(originFile, onlyTwoKeys);
+ const decryptedFile = await sdk2.decryptFile(encryptedFile, onlyTwoKeys[identity1]);
+
+ const decryptedString = await readFile(decryptedFile);
+
+ expect(originString).toBe(decryptedString);
+
+ try {
+ await sdk3.decryptFile(encryptedFile, onlyTwoKeys[identity1]);
+ } catch (e) {
+ return expect(e).toBeInstanceOf(Error);
+ }
+
+ throw new Error('should throw');
+ });
+
+ it('should take input as string, file or blob', async () => {
+ const keypair = virgilCrypto.generateKeys();
+
+ const originBlob = new Blob(['foo'], {
+ type: 'text/plain',
+ });
+
+ const encryptedFile = await sdk1.encryptFile(originFile, keypair.publicKey);
+ const encryptedBlob = await sdk1.encryptFile(originBlob, keypair.publicKey);
+
+ expect(encryptedFile).toBeInstanceOf(File);
+ expect(encryptedBlob).toBeInstanceOf(Blob);
+ expect(encryptedBlob).not.toBeInstanceOf(File);
+ });
+
+ it('should process different chunks of data', async () => {
+ const encryptedSnapshots: onEncryptProgressSnapshot[] = [];
+
+ const originString = 'foo';
+
+ const originFile = new File([originString], 'foo.txt', {
+ type: 'text/plain',
+ });
+
+ expect(originFile.size).toBe(3);
+
+ const encryptedFile = await sdk1.encryptFile(originFile, lookupResult[identity2], {
+ chunkSize: 2,
+ onProgress: encryptedSnapshots.push.bind(encryptedSnapshots),
+ });
+
+ expect(encryptedSnapshots.length).toEqual(4);
+ expect(encryptedSnapshots[0]).toMatchObject({
+ fileSize: originFile.size,
+ bytesProcessed: 2,
+ state: VIRGIL_STREAM_SIGNING_STATE,
+ });
+ expect(encryptedSnapshots[1]).toMatchObject({
+ fileSize: originFile.size,
+ bytesProcessed: 3,
+ state: VIRGIL_STREAM_SIGNING_STATE,
+ });
+ expect(encryptedSnapshots[2]).toMatchObject({
+ fileSize: originFile.size,
+ bytesProcessed: 2,
+ state: VIRGIL_STREAM_ENCRYPTING_STATE,
+ });
+ expect(encryptedSnapshots[3]).toMatchObject({
+ fileSize: originFile.size,
+ bytesProcessed: 3,
+ state: VIRGIL_STREAM_ENCRYPTING_STATE,
+ });
+
+ const decryptedSnapshots: onDecryptProgressSnapshot[] = [];
+
+ await sdk2.decryptFile(encryptedFile, lookupResult[identity1], {
+ chunkSize: Math.ceil(encryptedFile.size / 2),
+ onProgress: decryptedSnapshots.push.bind(decryptedSnapshots),
+ });
+
+ expect(decryptedSnapshots.length).toEqual(3);
+ expect(decryptedSnapshots[0]).toMatchObject({
+ fileSize: encryptedFile.size,
+ bytesProcessed: Math.ceil(encryptedFile.size / 2),
+ state: VIRGIL_STREAM_DECRYPTING_STATE,
+ });
+ expect(decryptedSnapshots[1]).toMatchObject({
+ fileSize: encryptedFile.size,
+ bytesProcessed: encryptedFile.size,
+ state: VIRGIL_STREAM_DECRYPTING_STATE,
+ });
+ expect(decryptedSnapshots[2]).toMatchObject({
+ fileSize: originFile.size,
+ bytesProcessed: originFile.size,
+ state: VIRGIL_STREAM_VERIFYING_STATE,
+ });
+ });
+
+ it('should abort encryptFile', async () => {
+ const encryptAbort = new AbortController();
+ const decryptAbort = new AbortController();
+
+ const encryptPromise = sdk1.encryptFile(originFile, lookupResult[identity2]);
+ const encryptAbortedPromise = sdk1.encryptFile(originFile, lookupResult[identity2], {
+ chunkSize: 1,
+ signal: encryptAbort.signal,
+ });
+
+ encryptAbort.abort();
+
+ try {
+ await encryptAbortedPromise;
+ } catch (err) {
+ expect(err).toBeInstanceOf(Error);
+ }
+ try {
+ await sdk1.decryptFile(await encryptPromise, lookupResult[identity1], {
+ chunkSize: Math.floor(originFile.size / 3),
+ signal: decryptAbort.signal,
+ onProgress: decryptAbort.abort,
+ });
+ } catch (err) {
+ expect(err).toBeInstanceOf(Error);
+ return;
+ }
+
+ throw new Error('should throw');
+ });
+
+ it('should verify the signature', async () => {
+ const receiverPublicKey = await sdk1.lookupPublicKeys(identity2);
+ const encryptedFile = await sdk1.encryptFile(originFile, receiverPublicKey);
+ try {
+ await sdk2.decryptFile(encryptedFile);
+ } catch (err) {
+ expect(err).toBeInstanceOf(IntegrityCheckFailedError);
+ return;
+ }
+ throw new Error('should throw');
+ });
+});
diff --git a/src/__tests__/utils.test.ts b/src/__tests__/utils.test.ts
index 29db3e5c..75154e80 100644
--- a/src/__tests__/utils.test.ts
+++ b/src/__tests__/utils.test.ts
@@ -53,6 +53,9 @@ export const createFetchToken = (identity: string) => () =>
export const initializeEThree = (fetchToken: () => Promise) =>
EThree.initialize(fetchToken, { apiUrl: process.env.API_URL });
+export const initializeETheeFromIdentity = (identity: string) =>
+ EThree.initialize(createFetchToken(identity));
+
export const createSyncStorage = async (identity: string, password: string) => {
const fetchToken = createFetchToken(identity);
@@ -78,3 +81,13 @@ export const createSyncStorage = async (identity: string, password: string) => {
};
export const clear = () => keyStorage.clear();
+
+export const readFile = (file: Blob) => {
+ const reader = new FileReader();
+
+ const promise = new Promise(r => reader.addEventListener('loadend', () => r(reader.result!)));
+
+ reader.readAsText(file);
+
+ return promise;
+};
diff --git a/src/errors.ts b/src/errors.ts
index 1aefa58b..745f1462 100644
--- a/src/errors.ts
+++ b/src/errors.ts
@@ -6,9 +6,17 @@ export const DUPLICATE_IDENTITIES = 'Identities in array should be unique';
* @hidden
*/
export const EMPTY_ARRAY = `Array should be non empty`;
+/**
+ * @hidden
+ */
+export const throwIllegalInvocationError = (method: string) => {
+ throw new Error(`Calling ${method} two or more times in a row is not allowed.`);
+};
+
/**
* Custom error class for errors specific to Virgil E3kit.
*/
+
export class SdkError extends Error {
name: string;
constructor(m: string, name: string = 'SdkError') {
@@ -116,3 +124,21 @@ export class LookupNotFoundError extends SdkError {
super(`${identity} not found`, 'LookupNotFoundError');
}
}
+
+/**
+ * Error thrown by {@link EThree.decryptFile} in case if signature of the file is not valid.
+ */
+export class IntegrityCheckFailedError extends SdkError {
+ constructor(message: string) {
+ super(message, 'IntegrityCheckFailedError');
+ }
+}
+
+/**
+ * Error thrown by {@link EThree.decryptFile} or {@link EThree.encryptFile} if user aborts an operation.
+ */
+export class AbortError extends SdkError {
+ constructor() {
+ super('Operation aborted by user', 'AbortError');
+ }
+}
diff --git a/src/index.ts b/src/index.ts
index 6f6a9873..a162c032 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,6 @@
import 'es6-symbol/implement';
-export { default as EThree } from './EThree';
+export * from './EThree';
export * from './errors';
+export * from './types';
+export { default as EThree } from './EThree';
diff --git a/src/types.ts b/src/types.ts
new file mode 100644
index 00000000..a453b497
--- /dev/null
+++ b/src/types.ts
@@ -0,0 +1,104 @@
+import { VirgilPublicKey } from 'virgil-crypto';
+import {
+ VIRGIL_STREAM_SIGNING_STATE,
+ VIRGIL_STREAM_ENCRYPTING_STATE,
+ VIRGIL_STREAM_VERIFYING_STATE,
+ VIRGIL_STREAM_DECRYPTING_STATE,
+} from './utils/constants';
+import { IKeyEntryStorage } from 'virgil-sdk';
+
+export interface EThreeInitializeOptions {
+ /**
+ * Implementation of IKeyEntryStorage. Used IndexedDB Key Storage from
+ * [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript) by default.
+ */
+ keyEntryStorage?: IKeyEntryStorage;
+ /**
+ * Url of the Card Services. Used for development purposes.
+ */
+ apiUrl?: string;
+}
+
+/**
+ * Dictionary returned from lookupPublicKey method
+ */
+
+export type LookupResult = {
+ [identity: string]: VirgilPublicKey;
+};
+
+/**
+ * Argument for encrypt function can be single VirgilPublicKey or LookupResult
+ */
+export type EncryptVirgilPublicKeyArg = LookupResult | VirgilPublicKey;
+
+/**
+ * Callback invoked for each chunk being processed in encryptFile method.
+ */
+export type onEncryptProgressCallback = (snapshot: onEncryptProgressSnapshot) => void;
+
+/**
+ * Callback invoked for each chunk being processed in decryptFile method.
+ */
+export type onDecryptProgressCallback = (snapshot: onDecryptProgressSnapshot) => void;
+
+interface onProgressSnapshot {
+ /**
+ * Total size of the file being processed.
+ */
+ fileSize: number;
+ /**
+ * Size of the file being encrypted in bytes.
+ */
+ bytesProcessed: number;
+}
+
+/**
+ * An argument of the onEncryptProgressCallback.
+ */
+export interface onEncryptProgressSnapshot extends onProgressSnapshot {
+ /**
+ * Current status of processing. Can be "Signing" then "Encrypting".
+ */
+ state: VIRGIL_STREAM_SIGNING_STATE | VIRGIL_STREAM_ENCRYPTING_STATE;
+}
+
+export interface onDecryptProgressSnapshot extends onProgressSnapshot {
+ /**
+ * Current status of processing. Can be "Decrypting" then "Verifying".
+ */
+ state: VIRGIL_STREAM_DECRYPTING_STATE | VIRGIL_STREAM_VERIFYING_STATE;
+}
+
+interface FileOptions {
+ /**
+ * Size of chunk being processed at one time. Bigger chunks make function execute faster, but
+ * consume more memory in one time and can cause a performance hit. Default value is 64kb.
+ */
+ chunkSize?: number;
+ /**
+ * Instance of `AbortSignal` which can be received from `AbortController`. Used to cancel encryptFile
+ * operation.
+ */
+ signal?: AbortSignal;
+}
+
+/**
+ * Options for encryptedFile method.
+ */
+export interface EncryptFileOptions extends FileOptions {
+ /**
+ * `onEncryptProgressCallback` parameter.
+ */
+ onProgress?: onEncryptProgressCallback;
+}
+
+/**
+ * Options for decryptedFile method.
+ */
+export interface DecryptFileOptions extends FileOptions {
+ /**
+ * `onDecryptProgressCallback` parameter.
+ */
+ onProgress?: onDecryptProgressCallback;
+}
diff --git a/src/utils/constants.ts b/src/utils/constants.ts
new file mode 100644
index 00000000..b1de31eb
--- /dev/null
+++ b/src/utils/constants.ts
@@ -0,0 +1,20 @@
+/**
+ * @hidden
+ */
+export const STORAGE_NAME = '.virgil-local-storage';
+/**
+ * @hidden
+ */
+export const DEFAULT_API_URL = 'https://api.virgilsecurity.com';
+
+export type VIRGIL_STREAM_SIGNING_STATE = 'Signing';
+export const VIRGIL_STREAM_SIGNING_STATE = 'Signing';
+
+export type VIRGIL_STREAM_ENCRYPTING_STATE = 'Encrypting';
+export const VIRGIL_STREAM_ENCRYPTING_STATE = 'Encrypting';
+
+export type VIRGIL_STREAM_DECRYPTING_STATE = 'Decrypting';
+export const VIRGIL_STREAM_DECRYPTING_STATE = 'Decrypting';
+
+export type VIRGIL_STREAM_VERIFYING_STATE = 'Verifying';
+export const VIRGIL_STREAM_VERIFYING_STATE = 'Verifying';
diff --git a/src/utils/innerTypes.ts b/src/utils/innerTypes.ts
new file mode 100644
index 00000000..b8b131d3
--- /dev/null
+++ b/src/utils/innerTypes.ts
@@ -0,0 +1,21 @@
+import { VirgilPrivateKey, VirgilPublicKey } from 'virgil-crypto';
+import { IAccessTokenProvider } from 'virgil-sdk';
+import { EThreeInitializeOptions } from '../types';
+
+/**
+ * @hidden
+ */
+export interface EThreeCtorOptions extends EThreeInitializeOptions {
+ /**
+ * Implementation of IAccessTokenProvider from [Virgil SDK](https://github.com/virgilsecurity/virgil-sdk-javascript);
+ */
+ accessTokenProvider: IAccessTokenProvider;
+}
+
+/**
+ * @hidden
+ */
+export type KeyPair = {
+ privateKey: VirgilPrivateKey;
+ publicKey: VirgilPublicKey;
+};
diff --git a/src/utils/processFile.ts b/src/utils/processFile.ts
new file mode 100644
index 00000000..27390f7d
--- /dev/null
+++ b/src/utils/processFile.ts
@@ -0,0 +1,73 @@
+import { AbortError } from '../errors';
+
+/**
+ * @hidden
+ */
+export type onChunkCallback = (chunk: string | ArrayBuffer, offset: number) => void;
+
+/**
+ * @hidden
+ */
+export type processFileOptions = {
+ file: Blob;
+ chunkSize: number;
+ signal?: AbortSignal;
+ onChunkCallback: onChunkCallback;
+ onFinishCallback: () => void;
+ onErrorCallback: (err: any) => void;
+};
+
+/**
+ * @hidden
+ */
+export function processFile({
+ file,
+ chunkSize,
+ signal,
+ onChunkCallback,
+ onFinishCallback,
+ onErrorCallback,
+}: processFileOptions) {
+ const reader = new FileReader();
+
+ const dataSize = file.size;
+
+ let offset = 0;
+ let endOffset = Math.min(offset + chunkSize, dataSize);
+
+ if (signal) {
+ const onAbort = () => {
+ reader.abort();
+ onErrorCallback(new AbortError());
+ };
+ if (signal.aborted) return onAbort();
+ else signal.addEventListener('abort', onAbort);
+ }
+
+ reader.onload = () => {
+ if (!reader.result) throw new Error('reader.result is null');
+
+ try {
+ onChunkCallback(reader.result, endOffset);
+ } catch (err) {
+ return onErrorCallback(err);
+ }
+
+ offset = endOffset;
+ endOffset = Math.min(offset + chunkSize, dataSize);
+
+ if (offset === dataSize) {
+ try {
+ onFinishCallback();
+ } catch (err) {
+ onErrorCallback(err);
+ }
+ } else {
+ reader.readAsArrayBuffer(file.slice(offset, endOffset));
+ }
+ };
+
+ reader.onerror = () => onErrorCallback(reader.error);
+
+ reader.readAsArrayBuffer(file.slice(offset, endOffset));
+}
diff --git a/src/utils/typeguards.ts b/src/utils/typeguards.ts
index babf7724..03637916 100644
--- a/src/utils/typeguards.ts
+++ b/src/utils/typeguards.ts
@@ -20,6 +20,18 @@ export const isWithoutErrors = (arr: Array): arr is Array => {
export const isString = (val: any): val is string => {
return typeof val === 'string';
};
+/**
+ * @hidden
+ */
+export const isBlob = (val: any): val is Blob => {
+ return val instanceof Blob;
+};
+/**
+ * @hidden
+ */
+export const isFile = (val: any): val is File => {
+ return val instanceof File;
+};
/**
* @hidden
*/
diff --git a/tsconfig.json b/tsconfig.json
index 7f3886d6..bc095f41 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,38 +1,39 @@
{
- "compilerOptions": {
- "target": "es5",
- "lib": [
- "es2015",
- "es2016",
- "es2017",
- "es2018"
+ "compilerOptions": {
+ "target": "es5",
+ "lib": [
+ "dom",
+ "es2015",
+ "es2016",
+ "es2017",
+ "es2018"
+ ],
+ "declaration": true,
+ "declarationDir": "./dist/types",
+ "strict": true,
+ "moduleResolution": "node",
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true,
+ "noUnusedLocals": true,
+ },
+ "include": [
+ "src"
],
- "declaration": true,
- "declarationDir": "./dist/types",
- "strict": true,
- "moduleResolution": "node",
- "esModuleInterop": true,
- "allowSyntheticDefaultImports": true,
- "noUnusedLocals": true,
- },
- "include": [
- "src"
- ],
- "typedocOptions": {
- "out": "docs",
- "mode": "file",
- "target": "ES6",
- "module": "es6",
- "moduleResolution": "node",
- "exclude": "**/__tests__/**",
- "ignoreCompilerErrors": true,
- "excludePrivate": true,
- "excludeNotExported": true,
- "stripInternal": true,
- "excludeExternals": true,
- "suppressExcessPropertyErrors": true,
- "suppressImplicitAnyIndexErrors": true,
- "hideGenerator": true,
- "readme": "none"
- }
+ "typedocOptions": {
+ "out": "docs",
+ "mode": "file",
+ "target": "ES6",
+ "module": "es6",
+ "moduleResolution": "node",
+ "exclude": "**/__tests__/**",
+ "ignoreCompilerErrors": true,
+ "excludePrivate": true,
+ "excludeNotExported": true,
+ "stripInternal": true,
+ "excludeExternals": true,
+ "suppressExcessPropertyErrors": true,
+ "suppressImplicitAnyIndexErrors": true,
+ "hideGenerator": true,
+ "readme": "none"
+ }
}