@opengovsg/formsg-sdk 0.15.0 → 7.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -9
- package/cjs-entry.cjs +5 -0
- package/dist/{crypto-base.js → cjs/crypto-base.js} +7 -9
- package/dist/{crypto.js → cjs/crypto.js} +2 -2
- package/dist/{index.d.ts → cjs/index.d.ts} +2 -2
- package/dist/{index.js → cjs/index.js} +12 -2
- package/dist/{util → cjs/util}/publicKey.js +2 -3
- package/dist/{util → cjs/util}/signature.js +19 -10
- package/dist/{util → cjs/util}/validate.js +2 -3
- package/dist/{util → cjs/util}/webhooks.js +17 -7
- package/dist/{webhooks.js → cjs/webhooks.js} +17 -7
- package/dist/esm/crypto-base.d.ts +25 -0
- package/dist/esm/crypto-base.js +86 -0
- package/dist/esm/crypto-v3.d.ts +41 -0
- package/dist/esm/crypto-v3.js +168 -0
- package/dist/esm/crypto.d.ts +41 -0
- package/dist/esm/crypto.js +228 -0
- package/dist/esm/errors.d.ts +13 -0
- package/dist/esm/errors.js +64 -0
- package/dist/esm/index.d.ts +20 -0
- package/dist/esm/index.js +39 -0
- package/dist/esm/resource/signing-keys.d.ts +16 -0
- package/dist/esm/resource/signing-keys.js +19 -0
- package/dist/esm/resource/verification-keys.d.ts +16 -0
- package/dist/esm/resource/verification-keys.js +19 -0
- package/dist/esm/types.d.ts +101 -0
- package/dist/esm/types.js +1 -0
- package/dist/esm/util/crypto.d.ts +42 -0
- package/dist/esm/util/crypto.js +74 -0
- package/dist/esm/util/parser.d.ts +24 -0
- package/dist/esm/util/parser.js +35 -0
- package/dist/esm/util/publicKey.d.ts +14 -0
- package/dist/esm/util/publicKey.js +38 -0
- package/dist/esm/util/signature.d.ts +16 -0
- package/dist/esm/util/signature.js +22 -0
- package/dist/esm/util/stage.d.ts +5 -0
- package/dist/esm/util/stage.js +7 -0
- package/dist/esm/util/validate.d.ts +4 -0
- package/dist/esm/util/validate.js +32 -0
- package/dist/esm/util/webhooks.d.ts +20 -0
- package/dist/esm/util/webhooks.js +33 -0
- package/dist/esm/verification/index.d.ts +18 -0
- package/dist/esm/verification/index.js +77 -0
- package/dist/esm/verification/utils.d.ts +12 -0
- package/dist/esm/verification/utils.js +18 -0
- package/dist/esm/webhooks.d.ts +48 -0
- package/dist/esm/webhooks.js +75 -0
- package/package.json +48 -32
- package/.eslintrc +0 -75
- package/.github/workflows/ci.yml +0 -53
- package/CHANGELOG.md +0 -177
- /package/dist/{crypto-base.d.ts → cjs/crypto-base.d.ts} +0 -0
- /package/dist/{crypto-v3.d.ts → cjs/crypto-v3.d.ts} +0 -0
- /package/dist/{crypto-v3.js → cjs/crypto-v3.js} +0 -0
- /package/dist/{crypto.d.ts → cjs/crypto.d.ts} +0 -0
- /package/dist/{errors.d.ts → cjs/errors.d.ts} +0 -0
- /package/dist/{errors.js → cjs/errors.js} +0 -0
- /package/dist/{resource → cjs/resource}/signing-keys.d.ts +0 -0
- /package/dist/{resource → cjs/resource}/signing-keys.js +0 -0
- /package/dist/{resource → cjs/resource}/verification-keys.d.ts +0 -0
- /package/dist/{resource → cjs/resource}/verification-keys.js +0 -0
- /package/dist/{types.d.ts → cjs/types.d.ts} +0 -0
- /package/dist/{types.js → cjs/types.js} +0 -0
- /package/dist/{util → cjs/util}/crypto.d.ts +0 -0
- /package/dist/{util → cjs/util}/crypto.js +0 -0
- /package/dist/{util → cjs/util}/parser.d.ts +0 -0
- /package/dist/{util → cjs/util}/parser.js +0 -0
- /package/dist/{util → cjs/util}/publicKey.d.ts +0 -0
- /package/dist/{util → cjs/util}/signature.d.ts +0 -0
- /package/dist/{util → cjs/util}/stage.d.ts +0 -0
- /package/dist/{util → cjs/util}/stage.js +0 -0
- /package/dist/{util → cjs/util}/validate.d.ts +0 -0
- /package/dist/{util → cjs/util}/webhooks.d.ts +0 -0
- /package/dist/{verification → cjs/verification}/index.d.ts +0 -0
- /package/dist/{verification → cjs/verification}/index.js +0 -0
- /package/dist/{verification → cjs/verification}/utils.d.ts +0 -0
- /package/dist/{verification → cjs/verification}/utils.js +0 -0
- /package/dist/{webhooks.d.ts → cjs/webhooks.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
_Please note that this is an SDK for webhooks integration, and_ **_not_** _the FormSG system._
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
# FormSG Javascript SDK
|
|
3
|
+
# FormSG JavaScript SDK
|
|
6
4
|
|
|
7
5
|
This SDK provides convenient utilities for verifying FormSG webhooks and decrypting submissions in JavaScript and Node.js.
|
|
8
6
|
|
|
9
|
-
|
|
7
|
+
This package used to live at [`opengovsg/formsg-javascript-sdk`](https://github.com/opengovsg/formsg-javascript-sdk) and is now developed in the main FormSG monorepo under [`packages/sdk`](./). It is still published to npm as [`@opengovsg/formsg-sdk`](https://www.npmjs.com/package/@opengovsg/formsg-sdk); starting with this migration the major version is bumped to `v7` to track the FormSG monorepo.
|
|
8
|
+
|
|
9
|
+
Not using JavaScript? Check out our sister SDKs:
|
|
10
10
|
- [formsg-python-sdk](https://github.com/opengovsg/formsg-python-sdk)
|
|
11
|
-
- [formsg-ruby-sdk](https://github.com/opengovsg/formsg-ruby-sdk)
|
|
12
11
|
|
|
13
12
|
## Installation
|
|
14
13
|
|
|
@@ -114,7 +113,7 @@ the shape
|
|
|
114
113
|
|
|
115
114
|
<pre>
|
|
116
115
|
{
|
|
117
|
-
responses: <a href="./src/types.ts
|
|
116
|
+
responses: <a href="./src/types.ts">FormField</a>[]
|
|
118
117
|
verified?: <a href="https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkt">Record<string, any></a>
|
|
119
118
|
}
|
|
120
119
|
</pre>
|
|
@@ -128,7 +127,7 @@ The `decryptParams.encryptedContent` field decrypts into an array of `FormField`
|
|
|
128
127
|
Furthermore, if `decryptParams.verifiedContent` exists, the function will
|
|
129
128
|
decrypt and open the signed decrypted content with the package's own
|
|
130
129
|
`signingPublicKey` in
|
|
131
|
-
[`signing-keys.ts`](
|
|
130
|
+
[`signing-keys.ts`](./src/resource/signing-keys.ts).
|
|
132
131
|
The resulting decrypted verifiedContent will be assigned to the `verified` key
|
|
133
132
|
of the returned object.
|
|
134
133
|
|
|
@@ -137,7 +136,7 @@ of the returned object.
|
|
|
137
136
|
|
|
138
137
|
Note that due to end-to-end encryption, FormSG servers are unable to verify the data format.
|
|
139
138
|
|
|
140
|
-
However, the `decrypt` function exposed by this library [validates](
|
|
139
|
+
However, the `decrypt` function exposed by this library [validates](./src/util/validate.ts) the decrypted content and will **return `null` if the
|
|
141
140
|
decrypted content does not contain all of the fields displayed in the schema below.**
|
|
142
141
|
|
|
143
142
|
| Key | Type | Description |
|
|
@@ -152,7 +151,7 @@ decrypted content does not contain all of the fields displayed in the schema bel
|
|
|
152
151
|
> Additional internal fields may be included in webhooks from time to time, which will then be published as part of our official schema once it is stable for public consumption. If you are applying your own validation, you should account for this e.g. by not rejecting the webhook if there are additional fields included.
|
|
153
152
|
|
|
154
153
|
The full schema can be viewed in
|
|
155
|
-
[`validate.ts`](
|
|
154
|
+
[`validate.ts`](./src/util/validate.ts).
|
|
156
155
|
|
|
157
156
|
If the decrypted content is the correct shape, then:
|
|
158
157
|
|
package/cjs-entry.cjs
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// CJS backward-compatibility shim.
|
|
2
|
+
// TypeScript compiles `export default function` to `exports.default = fn`,
|
|
3
|
+
// but CJS consumers expect `require('@opengovsg/formsg-sdk')` to return
|
|
4
|
+
// the function directly (matching the old v0.15.0 behavior).
|
|
5
|
+
module.exports = require('./dist/cjs/index.js').default
|
|
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
13
|
-
return g =
|
|
12
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
14
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
15
|
function step(op) {
|
|
16
16
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -79,14 +79,12 @@ var CryptoBase = /** @class */ (function () {
|
|
|
79
79
|
* @param encrypted.nonce The nonce as a base-64 string
|
|
80
80
|
* @param encrypted.blob The encrypted file as a Blob object
|
|
81
81
|
*/
|
|
82
|
-
this.decryptFile = function (
|
|
83
|
-
var filePublicKey =
|
|
84
|
-
return
|
|
85
|
-
return
|
|
86
|
-
return [2 /*return*/, tweetnacl_1.default.box.open(encryptedBinary, (0, tweetnacl_util_1.decodeBase64)(nonce), (0, tweetnacl_util_1.decodeBase64)(filePublicKey), (0, tweetnacl_util_1.decodeBase64)(secretKey))];
|
|
87
|
-
});
|
|
82
|
+
this.decryptFile = function (secretKey_1, _a) { return __awaiter(_this, [secretKey_1, _a], void 0, function (secretKey, _b) {
|
|
83
|
+
var filePublicKey = _b.submissionPublicKey, nonce = _b.nonce, encryptedBinary = _b.binary;
|
|
84
|
+
return __generator(this, function (_c) {
|
|
85
|
+
return [2 /*return*/, tweetnacl_1.default.box.open(encryptedBinary, (0, tweetnacl_util_1.decodeBase64)(nonce), (0, tweetnacl_util_1.decodeBase64)(filePublicKey), (0, tweetnacl_util_1.decodeBase64)(secretKey))];
|
|
88
86
|
});
|
|
89
|
-
};
|
|
87
|
+
}); };
|
|
90
88
|
}
|
|
91
89
|
return CryptoBase;
|
|
92
90
|
}());
|
|
@@ -24,8 +24,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
24
24
|
});
|
|
25
25
|
};
|
|
26
26
|
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
27
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
|
|
28
|
-
return g =
|
|
27
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
28
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
29
29
|
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
30
30
|
function step(op) {
|
|
31
31
|
if (f) throw new TypeError("Generator is already executing.");
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
export type { DecryptedContent, DecryptedContentV3, DecryptParams, DecryptParamsV3, EncryptedAttachmentContent, EncryptedAttachmentRecords, EncryptedContent, EncryptedContentV3, EncryptedFileContent, FieldType, FormField, FormFieldsV3, Keypair, PackageMode, VerificationOptions, } from './types';
|
|
1
2
|
import Crypto from './crypto';
|
|
2
3
|
import CryptoV3 from './crypto-v3';
|
|
3
4
|
import { PackageInitParams } from './types';
|
|
@@ -11,10 +12,9 @@ import Webhooks from './webhooks';
|
|
|
11
12
|
* @param {string?} [config.webhookSecretKey] Optional. base64 secret key for signing webhooks. If provided, enables generating signature and headers to authenticate webhook data.
|
|
12
13
|
* @param {VerificationOptions?} [config.verificationOptions] Optional. If provided, enables the usage of the verification module.
|
|
13
14
|
*/
|
|
14
|
-
|
|
15
|
+
export default function (config?: PackageInitParams): {
|
|
15
16
|
webhooks: Webhooks;
|
|
16
17
|
crypto: Crypto;
|
|
17
18
|
cryptoV3: CryptoV3;
|
|
18
19
|
verification: Verification;
|
|
19
20
|
};
|
|
20
|
-
export = _default;
|
|
@@ -2,12 +2,22 @@
|
|
|
2
2
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.default = default_1;
|
|
5
7
|
var publicKey_1 = require("./util/publicKey");
|
|
6
8
|
var crypto_1 = __importDefault(require("./crypto"));
|
|
7
9
|
var crypto_v3_1 = __importDefault(require("./crypto-v3"));
|
|
8
10
|
var verification_1 = __importDefault(require("./verification"));
|
|
9
11
|
var webhooks_1 = __importDefault(require("./webhooks"));
|
|
10
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Entrypoint into the FormSG SDK
|
|
14
|
+
*
|
|
15
|
+
* @param {PackageInitParams} config Package initialization config parameters
|
|
16
|
+
* @param {string?} [config.mode] Optional. Initializes public key used for verifying and decrypting in this package. If `config.signingPublicKey` is given, this param will be ignored.
|
|
17
|
+
* @param {string?} [config.webhookSecretKey] Optional. base64 secret key for signing webhooks. If provided, enables generating signature and headers to authenticate webhook data.
|
|
18
|
+
* @param {VerificationOptions?} [config.verificationOptions] Optional. If provided, enables the usage of the verification module.
|
|
19
|
+
*/
|
|
20
|
+
function default_1(config) {
|
|
11
21
|
if (config === void 0) { config = {}; }
|
|
12
22
|
var webhookSecretKey = config.webhookSecretKey, mode = config.mode, verificationOptions = config.verificationOptions;
|
|
13
23
|
/**
|
|
@@ -32,4 +42,4 @@ module.exports = function (config) {
|
|
|
32
42
|
transactionExpiry: verificationOptions === null || verificationOptions === void 0 ? void 0 : verificationOptions.transactionExpiry,
|
|
33
43
|
}),
|
|
34
44
|
};
|
|
35
|
-
}
|
|
45
|
+
}
|
|
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.getSigningPublicKey = getSigningPublicKey;
|
|
7
|
+
exports.getVerificationPublicKey = getVerificationPublicKey;
|
|
7
8
|
var signing_keys_1 = require("../resource/signing-keys");
|
|
8
9
|
var verification_keys_1 = require("../resource/verification-keys");
|
|
9
10
|
var stage_1 = __importDefault(require("./stage"));
|
|
@@ -24,7 +25,6 @@ function getSigningPublicKey(mode) {
|
|
|
24
25
|
return signing_keys_1.SIGNING_KEYS.production.publicKey;
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
|
-
exports.getSigningPublicKey = getSigningPublicKey;
|
|
28
28
|
/**
|
|
29
29
|
* Retrieves the appropriate verification public key.
|
|
30
30
|
* Defaults to production.
|
|
@@ -42,4 +42,3 @@ function getVerificationPublicKey(mode) {
|
|
|
42
42
|
return verification_keys_1.VERIFICATION_KEYS.production.publicKey;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
|
-
exports.getVerificationPublicKey = getVerificationPublicKey;
|
|
@@ -15,15 +15,26 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.
|
|
36
|
+
exports.sign = sign;
|
|
37
|
+
exports.verify = verify;
|
|
27
38
|
var tweetnacl = __importStar(require("tweetnacl"));
|
|
28
39
|
var tweetnacl_util_1 = require("tweetnacl-util");
|
|
29
40
|
/**
|
|
@@ -35,7 +46,6 @@ var tweetnacl_util_1 = require("tweetnacl-util");
|
|
|
35
46
|
function sign(basestring, secretKey) {
|
|
36
47
|
return (0, tweetnacl_util_1.encodeBase64)(tweetnacl.sign.detached((0, tweetnacl_util_1.decodeUTF8)(basestring), (0, tweetnacl_util_1.decodeBase64)(secretKey)));
|
|
37
48
|
}
|
|
38
|
-
exports.sign = sign;
|
|
39
49
|
/**
|
|
40
50
|
* Verifies a signature against a message and public key
|
|
41
51
|
* @param message The message to verify
|
|
@@ -46,4 +56,3 @@ exports.sign = sign;
|
|
|
46
56
|
function verify(message, signature, publicKey) {
|
|
47
57
|
return tweetnacl.sign.detached.verify((0, tweetnacl_util_1.decodeUTF8)(message), (0, tweetnacl_util_1.decodeBase64)(signature), (0, tweetnacl_util_1.decodeBase64)(publicKey));
|
|
48
58
|
}
|
|
49
|
-
exports.verify = verify;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.determineIsFormFields = determineIsFormFields;
|
|
4
|
+
exports.determineIsFormFieldsV3 = determineIsFormFieldsV3;
|
|
4
5
|
function determineIsFormFields(tbd) {
|
|
5
6
|
if (!Array.isArray(tbd)) {
|
|
6
7
|
return false;
|
|
@@ -21,7 +22,6 @@ function determineIsFormFields(tbd) {
|
|
|
21
22
|
});
|
|
22
23
|
return filter.length === tbd.length;
|
|
23
24
|
}
|
|
24
|
-
exports.determineIsFormFields = determineIsFormFields;
|
|
25
25
|
// TODO(MRF): This is currently very rudimentary, we should look at making this more specific where required.
|
|
26
26
|
function determineIsFormFieldsV3(tbd) {
|
|
27
27
|
for (var _i = 0, _a = Object.keys(tbd); _i < _a.length; _i++) {
|
|
@@ -33,4 +33,3 @@ function determineIsFormFieldsV3(tbd) {
|
|
|
33
33
|
}
|
|
34
34
|
return true;
|
|
35
35
|
}
|
|
36
|
-
exports.determineIsFormFieldsV3 = determineIsFormFieldsV3;
|
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
exports.hasEpochExpired = exports.isSignatureHeaderValid = void 0;
|
|
27
37
|
var url = __importStar(require("url"));
|
|
@@ -15,13 +15,23 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
|
|
|
15
15
|
}) : function(o, v) {
|
|
16
16
|
o["default"] = v;
|
|
17
17
|
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
};
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
25
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
36
|
var url = __importStar(require("url"));
|
|
27
37
|
var parser_1 = require("./util/parser");
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { EncryptedFileContent } from './types';
|
|
2
|
+
export default class CryptoBase {
|
|
3
|
+
/**
|
|
4
|
+
* Generates a new keypair for encryption.
|
|
5
|
+
* @returns The generated keypair.
|
|
6
|
+
*/
|
|
7
|
+
generate: () => import("./types").Keypair;
|
|
8
|
+
/**
|
|
9
|
+
* Encrypt given binary file with a unique keypair for each submission.
|
|
10
|
+
* @param binary The file to encrypt, should be a blob that is converted to Uint8Array binary
|
|
11
|
+
* @param publicKey The base-64 encoded public key
|
|
12
|
+
* @returns Promise holding the encrypted file
|
|
13
|
+
* @throws error if any of the encrypt methods fail
|
|
14
|
+
*/
|
|
15
|
+
encryptFile: (binary: Uint8Array, publicKey: string) => Promise<EncryptedFileContent>;
|
|
16
|
+
/**
|
|
17
|
+
* Decrypt the given encrypted file content.
|
|
18
|
+
* @param secretKey Secret key as a base-64 string
|
|
19
|
+
* @param encrypted Object returned from encryptFile function
|
|
20
|
+
* @param encrypted.submissionPublicKey The file's public key as a base-64 string
|
|
21
|
+
* @param encrypted.nonce The nonce as a base-64 string
|
|
22
|
+
* @param encrypted.blob The encrypted file as a Blob object
|
|
23
|
+
*/
|
|
24
|
+
decryptFile: (secretKey: string, { submissionPublicKey: filePublicKey, nonce, binary: encryptedBinary, }: EncryptedFileContent) => Promise<Uint8Array | null>;
|
|
25
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
import nacl from 'tweetnacl';
|
|
38
|
+
import { decodeBase64, encodeBase64 } from 'tweetnacl-util';
|
|
39
|
+
import { generateKeypair } from './util/crypto';
|
|
40
|
+
var CryptoBase = /** @class */ (function () {
|
|
41
|
+
function CryptoBase() {
|
|
42
|
+
var _this = this;
|
|
43
|
+
/**
|
|
44
|
+
* Generates a new keypair for encryption.
|
|
45
|
+
* @returns The generated keypair.
|
|
46
|
+
*/
|
|
47
|
+
this.generate = generateKeypair;
|
|
48
|
+
/**
|
|
49
|
+
* Encrypt given binary file with a unique keypair for each submission.
|
|
50
|
+
* @param binary The file to encrypt, should be a blob that is converted to Uint8Array binary
|
|
51
|
+
* @param publicKey The base-64 encoded public key
|
|
52
|
+
* @returns Promise holding the encrypted file
|
|
53
|
+
* @throws error if any of the encrypt methods fail
|
|
54
|
+
*/
|
|
55
|
+
this.encryptFile = function (binary, publicKey) { return __awaiter(_this, void 0, void 0, function () {
|
|
56
|
+
var fileKeypair, nonce;
|
|
57
|
+
return __generator(this, function (_a) {
|
|
58
|
+
fileKeypair = this.generate();
|
|
59
|
+
nonce = nacl.randomBytes(24);
|
|
60
|
+
return [2 /*return*/, {
|
|
61
|
+
//! NOTE: submissionPublicKey here is a misnomer as a new keypair is generated per file.
|
|
62
|
+
// The naming is only retained for backward-compatibility purposes.
|
|
63
|
+
submissionPublicKey: fileKeypair.publicKey,
|
|
64
|
+
nonce: encodeBase64(nonce),
|
|
65
|
+
binary: nacl.box(binary, nonce, decodeBase64(publicKey), decodeBase64(fileKeypair.secretKey)),
|
|
66
|
+
}];
|
|
67
|
+
});
|
|
68
|
+
}); };
|
|
69
|
+
/**
|
|
70
|
+
* Decrypt the given encrypted file content.
|
|
71
|
+
* @param secretKey Secret key as a base-64 string
|
|
72
|
+
* @param encrypted Object returned from encryptFile function
|
|
73
|
+
* @param encrypted.submissionPublicKey The file's public key as a base-64 string
|
|
74
|
+
* @param encrypted.nonce The nonce as a base-64 string
|
|
75
|
+
* @param encrypted.blob The encrypted file as a Blob object
|
|
76
|
+
*/
|
|
77
|
+
this.decryptFile = function (secretKey_1, _a) { return __awaiter(_this, [secretKey_1, _a], void 0, function (secretKey, _b) {
|
|
78
|
+
var filePublicKey = _b.submissionPublicKey, nonce = _b.nonce, encryptedBinary = _b.binary;
|
|
79
|
+
return __generator(this, function (_c) {
|
|
80
|
+
return [2 /*return*/, nacl.box.open(encryptedBinary, decodeBase64(nonce), decodeBase64(filePublicKey), decodeBase64(secretKey))];
|
|
81
|
+
});
|
|
82
|
+
}); };
|
|
83
|
+
}
|
|
84
|
+
return CryptoBase;
|
|
85
|
+
}());
|
|
86
|
+
export default CryptoBase;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import CryptoBase from './crypto-base';
|
|
2
|
+
import { DecryptedContentV3, DecryptParams, DecryptParamsV3, EncryptedContentV3 } from './types';
|
|
3
|
+
export default class CryptoV3 extends CryptoBase {
|
|
4
|
+
signingPublicKey?: string;
|
|
5
|
+
constructor({ signingPublicKey }?: {
|
|
6
|
+
signingPublicKey?: string;
|
|
7
|
+
});
|
|
8
|
+
/**
|
|
9
|
+
* Encrypt input with a unique keypair for each submission.
|
|
10
|
+
* @param msg The message to encrypt, will be stringified.
|
|
11
|
+
* @param form The base-64 encoded form public key for encrypting.
|
|
12
|
+
* @returns The encrypted basestring.
|
|
13
|
+
*/
|
|
14
|
+
encrypt: (msg: any, formPublicKey: string) => EncryptedContentV3;
|
|
15
|
+
/**
|
|
16
|
+
* Decrypts an encrypted submission and returns it.
|
|
17
|
+
* @param submissionSecretKey The base-64 encoded secret key for decrypting.
|
|
18
|
+
* @param decryptParams The params containing encrypted content and information.
|
|
19
|
+
* @param decryptParams.encryptedContent The encrypted content encoded with base-64.
|
|
20
|
+
* @param decryptParams.version The version of the payload.
|
|
21
|
+
* @returns The decrypted content if successful. Else, null will be returned.
|
|
22
|
+
*/
|
|
23
|
+
decryptFromSubmissionKey: (submissionSecretKey: string, decryptParams: DecryptParams) => DecryptedContentV3 | null;
|
|
24
|
+
/**
|
|
25
|
+
* Decrypts an encrypted submission and returns it.
|
|
26
|
+
* @param formSecretKey The base-64 encoded form secret key for decrypting the submission.
|
|
27
|
+
* @param decryptParams The params containing encrypted content, encrypted submission key and information.
|
|
28
|
+
* @param decryptParams.encryptedContent The encrypted content encoded with base-64.
|
|
29
|
+
* @param decryptParams.encryptedSubmissionSecretKey The encrypted submission secret key encoded with base-64.
|
|
30
|
+
* @param decryptParams.version The version of the payload. Used to determine the decryption process to decrypt the content with.
|
|
31
|
+
* @returns The decrypted content if successful. Else, null will be returned.
|
|
32
|
+
* @throws {MissingPublicKeyError} if a public key is not provided when instantiating this class and is needed for verifying signed content.
|
|
33
|
+
*/
|
|
34
|
+
decrypt: (formSecretKey: string, decryptParams: DecryptParamsV3) => DecryptedContentV3 | null;
|
|
35
|
+
/**
|
|
36
|
+
* Returns true if a pair of public & secret keys are associated with each other
|
|
37
|
+
* @param publicKey The public key to verify against.
|
|
38
|
+
* @param secretKey The private key to verify against.
|
|
39
|
+
*/
|
|
40
|
+
valid: (publicKey: string, secretKey: string) => boolean;
|
|
41
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
var __extends = (this && this.__extends) || (function () {
|
|
2
|
+
var extendStatics = function (d, b) {
|
|
3
|
+
extendStatics = Object.setPrototypeOf ||
|
|
4
|
+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
|
5
|
+
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
|
|
6
|
+
return extendStatics(d, b);
|
|
7
|
+
};
|
|
8
|
+
return function (d, b) {
|
|
9
|
+
if (typeof b !== "function" && b !== null)
|
|
10
|
+
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
|
|
11
|
+
extendStatics(d, b);
|
|
12
|
+
function __() { this.constructor = d; }
|
|
13
|
+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
|
14
|
+
};
|
|
15
|
+
})();
|
|
16
|
+
var __assign = (this && this.__assign) || function () {
|
|
17
|
+
__assign = Object.assign || function(t) {
|
|
18
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
19
|
+
s = arguments[i];
|
|
20
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
21
|
+
t[p] = s[p];
|
|
22
|
+
}
|
|
23
|
+
return t;
|
|
24
|
+
};
|
|
25
|
+
return __assign.apply(this, arguments);
|
|
26
|
+
};
|
|
27
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
28
|
+
var t = {};
|
|
29
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
30
|
+
t[p] = s[p];
|
|
31
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
32
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
33
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
34
|
+
t[p[i]] = s[p[i]];
|
|
35
|
+
}
|
|
36
|
+
return t;
|
|
37
|
+
};
|
|
38
|
+
import { decodeBase64, decodeUTF8, encodeBase64, encodeUTF8, } from 'tweetnacl-util';
|
|
39
|
+
import { decryptContent, encryptMessage, generateKeypair, verifySignedMessage, } from './util/crypto';
|
|
40
|
+
import { determineIsFormFieldsV3 } from './util/validate';
|
|
41
|
+
import CryptoBase from './crypto-base';
|
|
42
|
+
import { MissingPublicKeyError } from './errors';
|
|
43
|
+
var CryptoV3 = /** @class */ (function (_super) {
|
|
44
|
+
__extends(CryptoV3, _super);
|
|
45
|
+
function CryptoV3(_a) {
|
|
46
|
+
var _b = _a === void 0 ? {} : _a, signingPublicKey = _b.signingPublicKey;
|
|
47
|
+
var _this = _super.call(this) || this;
|
|
48
|
+
/**
|
|
49
|
+
* Encrypt input with a unique keypair for each submission.
|
|
50
|
+
* @param msg The message to encrypt, will be stringified.
|
|
51
|
+
* @param form The base-64 encoded form public key for encrypting.
|
|
52
|
+
* @returns The encrypted basestring.
|
|
53
|
+
*/
|
|
54
|
+
_this.encrypt = function (msg, formPublicKey) {
|
|
55
|
+
var submissionKeypair = generateKeypair();
|
|
56
|
+
var encryptedSubmissionSecretKey = encryptMessage(decodeBase64(submissionKeypair.secretKey), formPublicKey);
|
|
57
|
+
var processedMsg = decodeUTF8(JSON.stringify(msg));
|
|
58
|
+
var encryptedContent = encryptMessage(processedMsg, submissionKeypair.publicKey);
|
|
59
|
+
return {
|
|
60
|
+
submissionPublicKey: submissionKeypair.publicKey,
|
|
61
|
+
submissionSecretKey: submissionKeypair.secretKey,
|
|
62
|
+
encryptedContent: encryptedContent,
|
|
63
|
+
encryptedSubmissionSecretKey: encryptedSubmissionSecretKey,
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Decrypts an encrypted submission and returns it.
|
|
68
|
+
* @param submissionSecretKey The base-64 encoded secret key for decrypting.
|
|
69
|
+
* @param decryptParams The params containing encrypted content and information.
|
|
70
|
+
* @param decryptParams.encryptedContent The encrypted content encoded with base-64.
|
|
71
|
+
* @param decryptParams.version The version of the payload.
|
|
72
|
+
* @returns The decrypted content if successful. Else, null will be returned.
|
|
73
|
+
*/
|
|
74
|
+
_this.decryptFromSubmissionKey = function (submissionSecretKey, decryptParams) {
|
|
75
|
+
try {
|
|
76
|
+
var encryptedContent = decryptParams.encryptedContent, verifiedContent = decryptParams.verifiedContent;
|
|
77
|
+
// Do not return the transformed object in `_decrypt` function as a signed
|
|
78
|
+
// object is not encoded in UTF8 and is encoded in Base-64 instead.
|
|
79
|
+
var decryptedContent = decryptContent(submissionSecretKey, encryptedContent);
|
|
80
|
+
if (!decryptedContent) {
|
|
81
|
+
throw new Error('Failed to decrypt content');
|
|
82
|
+
}
|
|
83
|
+
var decryptedObject = JSON.parse(encodeUTF8(decryptedContent));
|
|
84
|
+
if (!determineIsFormFieldsV3(decryptedObject)) {
|
|
85
|
+
throw new Error('Decrypted object does not fit expected shape');
|
|
86
|
+
}
|
|
87
|
+
var returnedObject = {
|
|
88
|
+
submissionSecretKey: submissionSecretKey,
|
|
89
|
+
responses: decryptedObject,
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Note on verifiedContent decryption for cryptoV3:
|
|
93
|
+
* Although decryption is supported, verifiedContent encryption is not supported
|
|
94
|
+
* in cryptoV3 encrypt.
|
|
95
|
+
* This is to keep the encryption of verifiedContent and encryptedContent similar to storage mode - where
|
|
96
|
+
* verifiedContent and encryptedContent are defined and encrypted separately.
|
|
97
|
+
*/
|
|
98
|
+
// decrypt verifiedContent if it exists
|
|
99
|
+
if (verifiedContent) {
|
|
100
|
+
if (!_this.signingPublicKey) {
|
|
101
|
+
throw new MissingPublicKeyError('Public signing key must be provided when instantiating the Crypto class in order to verify verified content');
|
|
102
|
+
}
|
|
103
|
+
var decryptedVerifiedContent = decryptContent(submissionSecretKey, verifiedContent);
|
|
104
|
+
if (!decryptedVerifiedContent) {
|
|
105
|
+
// Returns null if decrypting verified content failed.
|
|
106
|
+
throw new Error('Failed to decrypt verified content');
|
|
107
|
+
}
|
|
108
|
+
var decryptedVerifiedObject = verifySignedMessage(decryptedVerifiedContent, _this.signingPublicKey);
|
|
109
|
+
returnedObject.verified = decryptedVerifiedObject;
|
|
110
|
+
}
|
|
111
|
+
return returnedObject;
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
// Should only throw if MissingPublicKeyError.
|
|
115
|
+
// This library should be able to be used to encrypt and decrypt content
|
|
116
|
+
// if the content does not contain verified fields.
|
|
117
|
+
if (err instanceof MissingPublicKeyError) {
|
|
118
|
+
throw err;
|
|
119
|
+
}
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Decrypts an encrypted submission and returns it.
|
|
125
|
+
* @param formSecretKey The base-64 encoded form secret key for decrypting the submission.
|
|
126
|
+
* @param decryptParams The params containing encrypted content, encrypted submission key and information.
|
|
127
|
+
* @param decryptParams.encryptedContent The encrypted content encoded with base-64.
|
|
128
|
+
* @param decryptParams.encryptedSubmissionSecretKey The encrypted submission secret key encoded with base-64.
|
|
129
|
+
* @param decryptParams.version The version of the payload. Used to determine the decryption process to decrypt the content with.
|
|
130
|
+
* @returns The decrypted content if successful. Else, null will be returned.
|
|
131
|
+
* @throws {MissingPublicKeyError} if a public key is not provided when instantiating this class and is needed for verifying signed content.
|
|
132
|
+
*/
|
|
133
|
+
_this.decrypt = function (formSecretKey, decryptParams) {
|
|
134
|
+
try {
|
|
135
|
+
var encryptedSubmissionSecretKey = decryptParams.encryptedSubmissionSecretKey, rest = __rest(decryptParams, ["encryptedSubmissionSecretKey"]);
|
|
136
|
+
var submissionSecretKey = decryptContent(formSecretKey, encryptedSubmissionSecretKey);
|
|
137
|
+
if (submissionSecretKey === null)
|
|
138
|
+
return null;
|
|
139
|
+
return _this.decryptFromSubmissionKey(encodeBase64(submissionSecretKey), rest);
|
|
140
|
+
}
|
|
141
|
+
catch (err) {
|
|
142
|
+
if (err instanceof MissingPublicKeyError) {
|
|
143
|
+
// rethrow to let the caller decide how to handle missing signing key
|
|
144
|
+
throw err;
|
|
145
|
+
}
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
/**
|
|
150
|
+
* Returns true if a pair of public & secret keys are associated with each other
|
|
151
|
+
* @param publicKey The public key to verify against.
|
|
152
|
+
* @param secretKey The private key to verify against.
|
|
153
|
+
*/
|
|
154
|
+
_this.valid = function (publicKey, secretKey) {
|
|
155
|
+
var _a;
|
|
156
|
+
var testResponse = {};
|
|
157
|
+
var internalValidationVersion = 3;
|
|
158
|
+
var cipherResponse = _this.encrypt(testResponse, publicKey);
|
|
159
|
+
// Use toString here since the return should be an empty array.
|
|
160
|
+
return (testResponse.toString() ===
|
|
161
|
+
((_a = _this.decrypt(secretKey, __assign(__assign({}, cipherResponse), { version: internalValidationVersion }))) === null || _a === void 0 ? void 0 : _a.responses.toString()));
|
|
162
|
+
};
|
|
163
|
+
_this.signingPublicKey = signingPublicKey;
|
|
164
|
+
return _this;
|
|
165
|
+
}
|
|
166
|
+
return CryptoV3;
|
|
167
|
+
}(CryptoBase));
|
|
168
|
+
export default CryptoV3;
|