@opengovsg/formsg-sdk 0.9.0 → 0.11.0

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.
@@ -6,13 +6,13 @@ on:
6
6
  jobs:
7
7
  build:
8
8
  name: build
9
- runs-on: ubuntu-18.04
9
+ runs-on: ubuntu-latest
10
10
  steps:
11
11
  - uses: actions/checkout@v2
12
12
  - name: Use Node.js
13
13
  uses: actions/setup-node@v1
14
14
  with:
15
- node-version: '10.x'
15
+ node-version: 18
16
16
  - name: Cache Node.js modules
17
17
  uses: actions/cache@v2
18
18
  with:
@@ -27,13 +27,13 @@ jobs:
27
27
  - run: npm run build
28
28
  test:
29
29
  name: test
30
- runs-on: ubuntu-18.04
30
+ runs-on: ubuntu-latest
31
31
  steps:
32
32
  - uses: actions/checkout@v2
33
33
  - name: Use Node.js
34
34
  uses: actions/setup-node@v1
35
35
  with:
36
- node-version: '10.x'
36
+ node-version: 18
37
37
  - name: Cache Node.js modules
38
38
  uses: actions/cache@v2
39
39
  with:
package/CHANGELOG.md ADDED
@@ -0,0 +1,120 @@
1
+ ### Changelog
2
+
3
+ All notable changes to this project will be documented in this file. Dates are displayed in UTC.
4
+
5
+ Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
+
7
+ #### [v0.10.0](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.9.0...v0.10.0)
8
+
9
+ > 16 December 2022
10
+
11
+ - fix: allow empty field titles in decrypted responses [`#86`](https://github.com/opengovsg/formsg-javascript-sdk/pull/86)
12
+ - chore: run npm audit fix and update relevant deps [`#80`](https://github.com/opengovsg/formsg-javascript-sdk/pull/80)
13
+ - chore(deps): Upgrade vulnerable axios version [`#78`](https://github.com/opengovsg/formsg-javascript-sdk/pull/78)
14
+ - chore: merge v0.9.0 into develop [`#76`](https://github.com/opengovsg/formsg-javascript-sdk/pull/76)
15
+ - fix: run npm audit fix so typescript packages are the correct versions [`2bdbf89`](https://github.com/opengovsg/formsg-javascript-sdk/commit/2bdbf897614833cc50605554ddaa82ea567b8a09)
16
+ - chore: bump version to v0.10.0 [`e094041`](https://github.com/opengovsg/formsg-javascript-sdk/commit/e0940414e529012afc03c54165f82e9f5ce16b12)
17
+
18
+ #### [v0.9.0](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.8.2...v0.9.0)
19
+
20
+ > 16 December 2022
21
+
22
+ - build: add separate keypairs for dev environment [`#73`](https://github.com/opengovsg/formsg-javascript-sdk/pull/73)
23
+ - docs: specify version for attachment functionality [`#72`](https://github.com/opengovsg/formsg-javascript-sdk/pull/72)
24
+ - build(ci): migrate to GitHub Actions [`#70`](https://github.com/opengovsg/formsg-javascript-sdk/pull/70)
25
+ - refactor(crypto): minor refactor of decryptWithAttachments [`#69`](https://github.com/opengovsg/formsg-javascript-sdk/pull/69)
26
+ - feat: Adding eslint functionality for the repository [`#66`](https://github.com/opengovsg/formsg-javascript-sdk/pull/66)
27
+ - build(deps): bump lodash from 4.17.19 to 4.17.21 [`#64`](https://github.com/opengovsg/formsg-javascript-sdk/pull/64)
28
+ - add downloadAndDecryptAttachments for downloading and decrypting attachments [`#62`](https://github.com/opengovsg/formsg-javascript-sdk/pull/62)
29
+ - build(deps): bump y18n from 4.0.0 to 4.0.1 [`#59`](https://github.com/opengovsg/formsg-javascript-sdk/pull/59)
30
+ - Update README.md [`#61`](https://github.com/opengovsg/formsg-javascript-sdk/pull/61)
31
+ - build: merge Release 0.8.4 back to develop branch [`#58`](https://github.com/opengovsg/formsg-javascript-sdk/pull/58)
32
+ - build: release v0.8.4-beta.0 [`#56`](https://github.com/opengovsg/formsg-javascript-sdk/pull/56)
33
+ - Revert "build(npm): update repo entry (#43)" [`#55`](https://github.com/opengovsg/formsg-javascript-sdk/pull/55)
34
+ - fix: update .npmignore to ignore misc unneeded files [`#54`](https://github.com/opengovsg/formsg-javascript-sdk/pull/54)
35
+ - ref: use mode init parameter again [`#52`](https://github.com/opengovsg/formsg-javascript-sdk/pull/52)
36
+ - chore: Update JSDoc and print warning message if deprecated mode parameter is used [`#51`](https://github.com/opengovsg/formsg-javascript-sdk/pull/51)
37
+ - fix(FormField): account for table responses [`#44`](https://github.com/opengovsg/formsg-javascript-sdk/pull/44)
38
+ - build(npm): update repo entry [`#43`](https://github.com/opengovsg/formsg-javascript-sdk/pull/43)
39
+ - feat: add more webhook tests to check for undefined params [`#41`](https://github.com/opengovsg/formsg-javascript-sdk/pull/41)
40
+ - Bump lodash from 4.17.15 to 4.17.19 [`#42`](https://github.com/opengovsg/formsg-javascript-sdk/pull/42)
41
+ - fix: JSON body parser required for demo code to work [`#40`](https://github.com/opengovsg/formsg-javascript-sdk/pull/40)
42
+ - refactor: update verification HOF to Verification class [`#38`](https://github.com/opengovsg/formsg-javascript-sdk/pull/38)
43
+ - refactor: update crypto HOF to Crypto class [`#36`](https://github.com/opengovsg/formsg-javascript-sdk/pull/36)
44
+ - refactor: update webhooks HOF to Webhooks class [`#34`](https://github.com/opengovsg/formsg-javascript-sdk/pull/34)
45
+ - docs: fix code snippet typos [`#37`](https://github.com/opengovsg/formsg-javascript-sdk/pull/37)
46
+ - feat: add publicKey param to package initialization parameters [`#33`](https://github.com/opengovsg/formsg-javascript-sdk/pull/33)
47
+ - chore: add `test-ci` script for Travis to run instead of `test` [`#32`](https://github.com/opengovsg/formsg-javascript-sdk/pull/32)
48
+ - Release 0.8.3 - Allow tolerance for clock drift when authenticating webhooks [`#47`](https://github.com/opengovsg/formsg-javascript-sdk/pull/47)
49
+ - fix(epoch): allow for possible clock drift [`a3ce917`](https://github.com/opengovsg/formsg-javascript-sdk/commit/a3ce917c6c38a387edcfad06ae5176b1f92b0a46)
50
+ - fix(epoch): allow for possible clock drift [`5ba253d`](https://github.com/opengovsg/formsg-javascript-sdk/commit/5ba253d61d04d3082f4d752ecfc9efd3639acc0f)
51
+ - chore: bump version to 0.9.0 [`32111b1`](https://github.com/opengovsg/formsg-javascript-sdk/commit/32111b1a2c85955a33d478dbc06966dda7261e33)
52
+
53
+ #### [v0.8.2](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.4.1...v0.8.2)
54
+
55
+ > 4 June 2020
56
+
57
+ - Release v0.8.2 - Patch for encrypting non-UTF8 characters [`#35`](https://github.com/opengovsg/formsg-javascript-sdk/pull/35)
58
+ - Release v0.8.1 - Export types [`#29`](https://github.com/opengovsg/formsg-javascript-sdk/pull/29)
59
+ - Fix: Export declared types in the package [`#28`](https://github.com/opengovsg/formsg-javascript-sdk/pull/28)
60
+ - Replace tweetnacl-util with StableLib [`#27`](https://github.com/opengovsg/formsg-javascript-sdk/pull/27)
61
+ - v0.8.0 - Update decrypt signature [`#25`](https://github.com/opengovsg/formsg-javascript-sdk/pull/25)
62
+ - Test and build coverage badges with TravsiCI and Coveralls.io [`#23`](https://github.com/opengovsg/formsg-javascript-sdk/pull/23)
63
+ - chore: update README for increased clarity on decrypt [`#22`](https://github.com/opengovsg/formsg-javascript-sdk/pull/22)
64
+ - v0.7.0 - Verification module for SDK [`#19`](https://github.com/opengovsg/formsg-javascript-sdk/pull/19)
65
+ - fix: use req.get() in README sample code [`#21`](https://github.com/opengovsg/formsg-javascript-sdk/pull/21)
66
+ - Enforce minimum level of test coverage [`#20`](https://github.com/opengovsg/formsg-javascript-sdk/pull/20)
67
+ - Update encrypt/decryptFile function signature from blob to UInt8Array [`#18`](https://github.com/opengovsg/formsg-javascript-sdk/pull/18)
68
+ - Utility functions for attachments [`#17`](https://github.com/opengovsg/formsg-javascript-sdk/pull/17)
69
+ - Replace Joi with custom validation [`#16`](https://github.com/opengovsg/formsg-javascript-sdk/pull/16)
70
+ - Link GitHub to package.json [`#15`](https://github.com/opengovsg/formsg-javascript-sdk/pull/15)
71
+ - Fix broken links in readme [`#14`](https://github.com/opengovsg/formsg-javascript-sdk/pull/14)
72
+ - Extend crypto module for verified fields and migrate to TypeScript [`#12`](https://github.com/opengovsg/formsg-javascript-sdk/pull/12)
73
+ - Patch readme sample code [`#11`](https://github.com/opengovsg/formsg-javascript-sdk/pull/11)
74
+
75
+ #### [v0.4.1](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.4.0...v0.4.1)
76
+
77
+ > 30 March 2020
78
+
79
+ - Release v0.4.1 - Remove dangling reference to source in require [`#10`](https://github.com/opengovsg/formsg-javascript-sdk/pull/10)
80
+
81
+ #### [v0.4.0](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.3.2...v0.4.0)
82
+
83
+ > 30 March 2020
84
+
85
+ - Pre-publish transpile pipeline with Babel [`#9`](https://github.com/opengovsg/formsg-javascript-sdk/pull/9)
86
+
87
+ #### [v0.3.2](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.3.1...v0.3.2)
88
+
89
+ > 30 March 2020
90
+
91
+ - Avoid default arguments in destructuring [`#8`](https://github.com/opengovsg/formsg-javascript-sdk/pull/8)
92
+
93
+ #### [v0.3.1](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.3.0...v0.3.1)
94
+
95
+ > 30 March 2020
96
+
97
+ - Destructure options in the function body [`#7`](https://github.com/opengovsg/formsg-javascript-sdk/pull/7)
98
+
99
+ #### [v0.3.0](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.2.0...v0.3.0)
100
+
101
+ > 24 March 2020
102
+
103
+ - Release 0.3.0 [`#5`](https://github.com/opengovsg/formsg-javascript-sdk/pull/5)
104
+ - Add cryptographic functions to SDK [`#4`](https://github.com/opengovsg/formsg-javascript-sdk/pull/4)
105
+ - Update readme to clarify that this repository is the SDK and not the FormSG system. [`#3`](https://github.com/opengovsg/formsg-javascript-sdk/pull/3)
106
+
107
+ #### [v0.2.0](https://github.com/opengovsg/formsg-javascript-sdk/compare/v0.1.1...v0.2.0)
108
+
109
+ > 2 March 2020
110
+
111
+ - Version 0.2.0 - Add signing functions, end-to-end testing [`#2`](https://github.com/opengovsg/formsg-javascript-sdk/pull/2)
112
+
113
+ #### v0.1.1
114
+
115
+ > 2 March 2020
116
+
117
+ - Version 0.1.1 - Readme, configuration bugfix [`#1`](https://github.com/opengovsg/formsg-javascript-sdk/pull/1)
118
+ - Add signature authentication [`a23a6ff`](https://github.com/opengovsg/formsg-javascript-sdk/commit/a23a6ffee1aaa65f805207b3f7ed17ed05590010)
119
+ - gitignore [`1b288fa`](https://github.com/opengovsg/formsg-javascript-sdk/commit/1b288fa9cff6df70efb09bf477570159516605e1)
120
+ - install dependencies [`d8fc078`](https://github.com/opengovsg/formsg-javascript-sdk/commit/d8fc078b29ffb0043adbb105fe4a39abed5a8cf9)
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Open Government Products
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -7,6 +7,10 @@ _Please note that this is an SDK for webhooks integration, and_ **_not_** _the F
7
7
 
8
8
  This SDK provides convenient utilities for verifying FormSG webhooks and decrypting submissions in JavaScript and Node.js.
9
9
 
10
+ Not using Javascript? Check out our sister SDKs:
11
+ - [formsg-python-sdk](https://github.com/opengovsg/formsg-python-sdk)
12
+ - [formsg-ruby-sdk](https://github.com/opengovsg/formsg-ruby-sdk)
13
+
10
14
  ## Installation
11
15
 
12
16
  Install the package with
@@ -132,7 +136,7 @@ of the returned object.
132
136
  Note that due to end-to-end encryption, FormSG servers are unable to verify the data format.
133
137
 
134
138
  However, the `decrypt` function exposed by this library [validates](https://github.com/opengovsg/formsg-javascript-sdk/blob/master/src/util/validate.ts) the decrypted content and will **return `null` if the
135
- decrypted content does not fit the schema displayed below.**
139
+ decrypted content does not contain all of the fields displayed in the schema below.**
136
140
 
137
141
  | Key | Type | Description |
138
142
  | ----------- | -------- | -------------------------------------------------------------------------------------------------------- |
@@ -142,6 +146,9 @@ decrypted content does not fit the schema displayed below.**
142
146
  | fieldType | string | The type of field for the question. |
143
147
  | \_id | string | A unique identifier of the form field. WARNING: Changes when new fields are created/removed in the form. |
144
148
 
149
+ **Important Note: **
150
+ 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.
151
+
145
152
  The full schema can be viewed in
146
153
  [`validate.ts`](https://github.com/opengovsg/formsg-javascript-sdk/tree/master/src/util/validate.ts).
147
154
 
package/dist/crypto.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DecryptedContent, DecryptedContentAndAttachments, DecryptParams, EncryptedFileContent } from './types';
1
+ import { DecryptedContent, DecryptedContentAndAttachments, DecryptParams, EncryptedContent, EncryptedFileContent } from './types';
2
2
  export default class Crypto {
3
3
  signingPublicKey?: string;
4
4
  constructor({ signingPublicKey }?: {
@@ -11,7 +11,7 @@ export default class Crypto {
11
11
  * @param signingPrivateKey Optional. Must be a base-64 encoded private key. If given, will be used to signing the given msg param prior to encrypting.
12
12
  * @returns The encrypted basestring.
13
13
  */
14
- encrypt: (msg: any, encryptionPublicKey: string, signingPrivateKey?: string | undefined) => string;
14
+ encrypt: (msg: any, encryptionPublicKey: string, signingPrivateKey?: string) => EncryptedContent;
15
15
  /**
16
16
  * Decrypts an encrypted submission and returns it.
17
17
  * @param formSecretKey The base-64 secret key of the form to decrypt with.
package/dist/crypto.js CHANGED
@@ -14,7 +14,7 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
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.");
17
- while (_) try {
17
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
18
18
  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;
19
19
  if (y = 0, t) op = [op[0] & 2, t.value];
20
20
  switch (op[0]) {
@@ -47,8 +47,8 @@ var validate_1 = require("./util/validate");
47
47
  var errors_1 = require("./errors");
48
48
  var Crypto = /** @class */ (function () {
49
49
  function Crypto(_a) {
50
+ var _b = _a === void 0 ? {} : _a, signingPublicKey = _b.signingPublicKey;
50
51
  var _this = this;
51
- var signingPublicKey = (_a === void 0 ? {} : _a).signingPublicKey;
52
52
  /**
53
53
  * Encrypt input with a unique keypair for each submission
54
54
  * @param encryptionPublicKey The base-64 encoded public key for encrypting.
@@ -57,11 +57,11 @@ var Crypto = /** @class */ (function () {
57
57
  * @returns The encrypted basestring.
58
58
  */
59
59
  this.encrypt = function (msg, encryptionPublicKey, signingPrivateKey) {
60
- var processedMsg = tweetnacl_util_1.decodeUTF8(JSON.stringify(msg));
60
+ var processedMsg = (0, tweetnacl_util_1.decodeUTF8)(JSON.stringify(msg));
61
61
  if (signingPrivateKey) {
62
- processedMsg = tweetnacl_1.default.sign(processedMsg, tweetnacl_util_1.decodeBase64(signingPrivateKey));
62
+ processedMsg = tweetnacl_1.default.sign(processedMsg, (0, tweetnacl_util_1.decodeBase64)(signingPrivateKey));
63
63
  }
64
- return crypto_1.encryptMessage(processedMsg, encryptionPublicKey);
64
+ return (0, crypto_1.encryptMessage)(processedMsg, encryptionPublicKey);
65
65
  };
66
66
  /**
67
67
  * Decrypts an encrypted submission and returns it.
@@ -78,12 +78,12 @@ var Crypto = /** @class */ (function () {
78
78
  var encryptedContent = decryptParams.encryptedContent, verifiedContent = decryptParams.verifiedContent;
79
79
  // Do not return the transformed object in `_decrypt` function as a signed
80
80
  // object is not encoded in UTF8 and is encoded in Base-64 instead.
81
- var decryptedContent = crypto_1.decryptContent(formSecretKey, encryptedContent);
81
+ var decryptedContent = (0, crypto_1.decryptContent)(formSecretKey, encryptedContent);
82
82
  if (!decryptedContent) {
83
83
  throw new Error('Failed to decrypt content');
84
84
  }
85
- var decryptedObject = JSON.parse(tweetnacl_util_1.encodeUTF8(decryptedContent));
86
- if (!validate_1.determineIsFormFields(decryptedObject)) {
85
+ var decryptedObject = JSON.parse((0, tweetnacl_util_1.encodeUTF8)(decryptedContent));
86
+ if (!(0, validate_1.determineIsFormFields)(decryptedObject)) {
87
87
  throw new Error('Decrypted object does not fit expected shape');
88
88
  }
89
89
  var returnedObject = {
@@ -96,12 +96,12 @@ var Crypto = /** @class */ (function () {
96
96
  // Only care if it is the correct shape if verifiedContent exists, since
97
97
  // we need to append it to the end.
98
98
  // Decrypted message must be able to be authenticated by the public key.
99
- var decryptedVerifiedContent = crypto_1.decryptContent(formSecretKey, verifiedContent);
99
+ var decryptedVerifiedContent = (0, crypto_1.decryptContent)(formSecretKey, verifiedContent);
100
100
  if (!decryptedVerifiedContent) {
101
101
  // Returns null if decrypting verified content failed.
102
102
  throw new Error('Failed to decrypt verified content');
103
103
  }
104
- var decryptedVerifiedObject = crypto_1.verifySignedMessage(decryptedVerifiedContent, _this.signingPublicKey);
104
+ var decryptedVerifiedObject = (0, crypto_1.verifySignedMessage)(decryptedVerifiedContent, _this.signingPublicKey);
105
105
  returnedObject.verified = decryptedVerifiedObject;
106
106
  }
107
107
  return returnedObject;
@@ -132,10 +132,11 @@ var Crypto = /** @class */ (function () {
132
132
  var internalValidationVersion = 1;
133
133
  var cipherResponse = _this.encrypt(testResponse, publicKey);
134
134
  // Use toString here since the return should be an empty array.
135
- return (testResponse.toString() === ((_a = _this.decrypt(secretKey, {
136
- encryptedContent: cipherResponse,
137
- version: internalValidationVersion,
138
- })) === null || _a === void 0 ? void 0 : _a.responses.toString()));
135
+ return (testResponse.toString() ===
136
+ ((_a = _this.decrypt(secretKey, {
137
+ encryptedContent: cipherResponse,
138
+ version: internalValidationVersion,
139
+ })) === null || _a === void 0 ? void 0 : _a.responses.toString()));
139
140
  };
140
141
  /**
141
142
  * Encrypt given binary file with a unique keypair for each submission.
@@ -151,8 +152,8 @@ var Crypto = /** @class */ (function () {
151
152
  nonce = tweetnacl_1.default.randomBytes(24);
152
153
  return [2 /*return*/, {
153
154
  submissionPublicKey: submissionKeypair.publicKey,
154
- nonce: tweetnacl_util_1.encodeBase64(nonce),
155
- binary: tweetnacl_1.default.box(binary, nonce, tweetnacl_util_1.decodeBase64(formPublicKey), tweetnacl_util_1.decodeBase64(submissionKeypair.secretKey)),
155
+ nonce: (0, tweetnacl_util_1.encodeBase64)(nonce),
156
+ binary: tweetnacl_1.default.box(binary, nonce, (0, tweetnacl_util_1.decodeBase64)(formPublicKey), (0, tweetnacl_util_1.decodeBase64)(submissionKeypair.secretKey)),
156
157
  }];
157
158
  });
158
159
  }); };
@@ -168,7 +169,7 @@ var Crypto = /** @class */ (function () {
168
169
  var submissionPublicKey = _a.submissionPublicKey, nonce = _a.nonce, encryptedBinary = _a.binary;
169
170
  return __awaiter(_this, void 0, void 0, function () {
170
171
  return __generator(this, function (_b) {
171
- return [2 /*return*/, tweetnacl_1.default.box.open(encryptedBinary, tweetnacl_util_1.decodeBase64(nonce), tweetnacl_util_1.decodeBase64(submissionPublicKey), tweetnacl_util_1.decodeBase64(formSecretKey))];
172
+ return [2 /*return*/, tweetnacl_1.default.box.open(encryptedBinary, (0, tweetnacl_util_1.decodeBase64)(nonce), (0, tweetnacl_util_1.decodeBase64)(submissionPublicKey), (0, tweetnacl_util_1.decodeBase64)(formSecretKey))];
172
173
  });
173
174
  });
174
175
  };
@@ -202,7 +203,7 @@ var Crypto = /** @class */ (function () {
202
203
  });
203
204
  fieldIds = Object.keys(attachmentRecords);
204
205
  // Check if all fieldIds are within filenames
205
- if (!crypto_1.areAttachmentFieldIdsValid(fieldIds, filenames)) {
206
+ if (!(0, crypto_1.areAttachmentFieldIdsValid)(fieldIds, filenames)) {
206
207
  return [2 /*return*/, null];
207
208
  }
208
209
  downloadPromises = fieldIds.map(function (fieldId) {
@@ -214,7 +215,7 @@ var Crypto = /** @class */ (function () {
214
215
  // Decrypt all the attachments
215
216
  .then(function (_a) {
216
217
  var downloadResponse = _a.data;
217
- var encryptedFile = crypto_1.convertEncryptedAttachmentToFileContent(downloadResponse);
218
+ var encryptedFile = (0, crypto_1.convertEncryptedAttachmentToFileContent)(downloadResponse);
218
219
  return _this.decryptFile(formSecretKey, encryptedFile);
219
220
  })
220
221
  .then(function (decryptedFile) {
package/dist/errors.js CHANGED
@@ -3,16 +3,19 @@ var __extends = (this && this.__extends) || (function () {
3
3
  var extendStatics = function (d, b) {
4
4
  extendStatics = Object.setPrototypeOf ||
5
5
  ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
6
- function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
7
7
  return extendStatics(d, b);
8
8
  };
9
9
  return function (d, b) {
10
+ if (typeof b !== "function" && b !== null)
11
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
10
12
  extendStatics(d, b);
11
13
  function __() { this.constructor = d; }
12
14
  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
13
15
  };
14
16
  })();
15
17
  Object.defineProperty(exports, "__esModule", { value: true });
18
+ exports.AttachmentDecryptionError = exports.WebhookAuthenticateError = exports.MissingPublicKeyError = exports.MissingSecretKeyError = void 0;
16
19
  var MissingSecretKeyError = /** @class */ (function (_super) {
17
20
  __extends(MissingSecretKeyError, _super);
18
21
  function MissingSecretKeyError(message) {
package/dist/index.d.ts CHANGED
@@ -2,11 +2,6 @@ import Crypto from './crypto';
2
2
  import { PackageInitParams } from './types';
3
3
  import Verification from './verification';
4
4
  import Webhooks from './webhooks';
5
- declare const _default: (config?: PackageInitParams) => {
6
- webhooks: Webhooks;
7
- crypto: Crypto;
8
- verification: Verification;
9
- };
10
5
  /**
11
6
  * Entrypoint into the FormSG SDK
12
7
  *
@@ -15,4 +10,9 @@ declare const _default: (config?: PackageInitParams) => {
15
10
  * @param {string?} [config.webhookSecretKey] Optional. base64 secret key for signing webhooks. If provided, enables generating signature and headers to authenticate webhook data.
16
11
  * @param {VerificationOptions?} [config.verificationOptions] Optional. If provided, enables the usage of the verification module.
17
12
  */
13
+ declare const _default: (config?: PackageInitParams) => {
14
+ webhooks: Webhooks;
15
+ crypto: Crypto;
16
+ verification: Verification;
17
+ };
18
18
  export = _default;
package/dist/index.js CHANGED
@@ -13,11 +13,11 @@ module.exports = function (config) {
13
13
  * Public key is used for decrypting signed verified content in the `crypto` module, and
14
14
  * also for verifying webhook signatures' authenticity in the `wehbooks` module.
15
15
  */
16
- var signingPublicKey = publicKey_1.getSigningPublicKey(mode || 'production');
16
+ var signingPublicKey = (0, publicKey_1.getSigningPublicKey)(mode || 'production');
17
17
  /**
18
18
  * Public key is used for verifying verified field signatures' authenticity in the `verification` module.
19
19
  */
20
- var verificationPublicKey = publicKey_1.getVerificationPublicKey(mode || 'production');
20
+ var verificationPublicKey = (0, publicKey_1.getVerificationPublicKey)(mode || 'production');
21
21
  return {
22
22
  webhooks: new webhooks_1.default({
23
23
  publicKey: signingPublicKey,
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SIGNING_KEYS = void 0;
3
4
  // keys generated using nacl.sign.keyPair() from tweetnacl
4
5
  exports.SIGNING_KEYS = {
5
6
  staging: {
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERIFICATION_KEYS = void 0;
3
4
  // keys generated using nacl.sign.keyPair() from tweetnacl
4
5
  exports.VERIFICATION_KEYS = {
5
6
  staging: {
package/dist/types.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export declare type PackageInitParams = {
1
+ export type PackageInitParams = {
2
2
  /** base64 secret key for signing webhooks. If provided, enables generating signature and headers to authenticate webhook data. */
3
3
  webhookSecretKey?: string;
4
4
  /** If provided, enables the usage of the verification module. */
@@ -6,8 +6,8 @@ export declare type PackageInitParams = {
6
6
  /** Initializes public key used for verifying and decrypting in this package. If not given, will default to "production". */
7
7
  mode?: PackageMode;
8
8
  };
9
- export declare type FieldType = 'section' | 'radiobutton' | 'dropdown' | 'checkbox' | 'nric' | 'email' | 'table' | 'number' | 'rating' | 'yes_no' | 'decimal' | 'textfield' | 'textarea' | 'attachment' | 'date' | 'mobile' | 'homeno';
10
- export declare type FormField = {
9
+ export type FieldType = 'section' | 'radiobutton' | 'dropdown' | 'checkbox' | 'nric' | 'email' | 'table' | 'number' | 'rating' | 'yes_no' | 'decimal' | 'textfield' | 'textarea' | 'attachment' | 'date' | 'mobile' | 'homeno';
10
+ export type FormField = {
11
11
  _id: string;
12
12
  question: string;
13
13
  fieldType: FieldType;
@@ -20,61 +20,61 @@ export declare type FormField = {
20
20
  answer?: never;
21
21
  answerArray: string[] | string[][];
22
22
  });
23
- export declare type EncryptedContent = string;
24
- export declare type EncryptedAttachmentRecords = Record<string, string>;
23
+ export type EncryptedContent = string;
24
+ export type EncryptedAttachmentRecords = Record<string, string>;
25
25
  export interface DecryptParams {
26
26
  encryptedContent: EncryptedContent;
27
27
  version: number;
28
28
  verifiedContent?: EncryptedContent;
29
29
  attachmentDownloadUrls?: EncryptedAttachmentRecords;
30
30
  }
31
- export declare type DecryptedContent = {
31
+ export type DecryptedContent = {
32
32
  responses: FormField[];
33
33
  verified?: Record<string, any>;
34
34
  };
35
- export declare type DecryptedFile = {
35
+ export type DecryptedFile = {
36
36
  filename: string;
37
37
  content: Uint8Array;
38
38
  };
39
- export declare type DecryptedAttachments = Record<string, DecryptedFile>;
40
- export declare type DecryptedContentAndAttachments = {
39
+ export type DecryptedAttachments = Record<string, DecryptedFile>;
40
+ export type DecryptedContentAndAttachments = {
41
41
  content: DecryptedContent;
42
42
  attachments: DecryptedAttachments;
43
43
  };
44
- export declare type EncryptedFileContent = {
44
+ export type EncryptedFileContent = {
45
45
  submissionPublicKey: string;
46
46
  nonce: string;
47
47
  binary: Uint8Array;
48
48
  };
49
- export declare type EncryptedAttachmentContent = {
49
+ export type EncryptedAttachmentContent = {
50
50
  encryptedFile: {
51
51
  submissionPublicKey: string;
52
52
  nonce: string;
53
53
  binary: string;
54
54
  };
55
55
  };
56
- export declare type Keypair = {
56
+ export type Keypair = {
57
57
  publicKey: string;
58
58
  secretKey: string;
59
59
  };
60
- export declare type PackageMode = 'staging' | 'production' | 'development' | 'test';
61
- export declare type VerificationOptions = {
60
+ export type PackageMode = 'staging' | 'production' | 'development' | 'test';
61
+ export type VerificationOptions = {
62
62
  publicKey?: string;
63
63
  secretKey?: string;
64
64
  transactionExpiry?: number;
65
65
  };
66
- export declare type VerifiedAnswer = {
66
+ export type VerifiedAnswer = {
67
67
  fieldId: string;
68
68
  answer: string;
69
69
  };
70
- export declare type VerificationSignatureOptions = VerifiedAnswer & {
70
+ export type VerificationSignatureOptions = VerifiedAnswer & {
71
71
  transactionId: string;
72
72
  formId: string;
73
73
  };
74
- export declare type VerificationBasestringOptions = VerificationSignatureOptions & {
74
+ export type VerificationBasestringOptions = VerificationSignatureOptions & {
75
75
  time: number;
76
76
  };
77
- export declare type VerificationAuthenticateOptions = VerifiedAnswer & {
77
+ export type VerificationAuthenticateOptions = VerifiedAnswer & {
78
78
  signatureString: string;
79
79
  submissionCreatedAt: number;
80
80
  };
@@ -1,4 +1,4 @@
1
- import { Keypair, EncryptedAttachmentContent, EncryptedFileContent } from '../types';
1
+ import { Keypair, EncryptedContent, EncryptedAttachmentContent, EncryptedFileContent } from '../types';
2
2
  /**
3
3
  * Helper method to generate a new keypair for encryption.
4
4
  * @returns The generated keypair.
@@ -11,14 +11,14 @@ export declare const generateKeypair: () => Keypair;
11
11
  * @returns The encrypted basestring
12
12
  * @throws error if any of the encrypt methods fail
13
13
  */
14
- export declare const encryptMessage: (msg: Uint8Array, theirPublicKey: string) => string;
14
+ export declare const encryptMessage: (msg: Uint8Array, theirPublicKey: string) => EncryptedContent;
15
15
  /**
16
16
  * Helper method to decrypt an encrypted submission.
17
17
  * @param formPrivateKey base64
18
18
  * @param encryptedContent encrypted string encoded in base64
19
19
  * @return The decrypted content, or null if decryption failed.
20
20
  */
21
- export declare const decryptContent: (formPrivateKey: string, encryptedContent: string) => Uint8Array | null;
21
+ export declare const decryptContent: (formPrivateKey: string, encryptedContent: EncryptedContent) => Uint8Array | null;
22
22
  /**
23
23
  * Helper method to verify a signed message.
24
24
  * @param msg the message to verify
@@ -3,19 +3,21 @@ 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.convertEncryptedAttachmentToFileContent = exports.areAttachmentFieldIdsValid = exports.verifySignedMessage = exports.decryptContent = exports.encryptMessage = exports.generateKeypair = void 0;
6
7
  var tweetnacl_1 = __importDefault(require("tweetnacl"));
7
8
  var tweetnacl_util_1 = require("tweetnacl-util");
8
9
  /**
9
10
  * Helper method to generate a new keypair for encryption.
10
11
  * @returns The generated keypair.
11
12
  */
12
- exports.generateKeypair = function () {
13
+ var generateKeypair = function () {
13
14
  var kp = tweetnacl_1.default.box.keyPair();
14
15
  return {
15
- publicKey: tweetnacl_util_1.encodeBase64(kp.publicKey),
16
- secretKey: tweetnacl_util_1.encodeBase64(kp.secretKey),
16
+ publicKey: (0, tweetnacl_util_1.encodeBase64)(kp.publicKey),
17
+ secretKey: (0, tweetnacl_util_1.encodeBase64)(kp.secretKey),
17
18
  };
18
19
  };
20
+ exports.generateKeypair = generateKeypair;
19
21
  /**
20
22
  * Helper function to encrypt input with a unique keypair for each submission.
21
23
  * @param msg The message to encrypt
@@ -23,28 +25,30 @@ exports.generateKeypair = function () {
23
25
  * @returns The encrypted basestring
24
26
  * @throws error if any of the encrypt methods fail
25
27
  */
26
- exports.encryptMessage = function (msg, theirPublicKey) {
27
- var submissionKeypair = exports.generateKeypair();
28
+ var encryptMessage = function (msg, theirPublicKey) {
29
+ var submissionKeypair = (0, exports.generateKeypair)();
28
30
  var nonce = tweetnacl_1.default.randomBytes(24);
29
- var encrypted = tweetnacl_util_1.encodeBase64(tweetnacl_1.default.box(msg, nonce, tweetnacl_util_1.decodeBase64(theirPublicKey), tweetnacl_util_1.decodeBase64(submissionKeypair.secretKey)));
30
- return submissionKeypair.publicKey + ";" + tweetnacl_util_1.encodeBase64(nonce) + ":" + encrypted;
31
+ var encrypted = (0, tweetnacl_util_1.encodeBase64)(tweetnacl_1.default.box(msg, nonce, (0, tweetnacl_util_1.decodeBase64)(theirPublicKey), (0, tweetnacl_util_1.decodeBase64)(submissionKeypair.secretKey)));
32
+ return "".concat(submissionKeypair.publicKey, ";").concat((0, tweetnacl_util_1.encodeBase64)(nonce), ":").concat(encrypted);
31
33
  };
34
+ exports.encryptMessage = encryptMessage;
32
35
  /**
33
36
  * Helper method to decrypt an encrypted submission.
34
37
  * @param formPrivateKey base64
35
38
  * @param encryptedContent encrypted string encoded in base64
36
39
  * @return The decrypted content, or null if decryption failed.
37
40
  */
38
- exports.decryptContent = function (formPrivateKey, encryptedContent) {
41
+ var decryptContent = function (formPrivateKey, encryptedContent) {
39
42
  try {
40
43
  var _a = encryptedContent.split(';'), submissionPublicKey = _a[0], nonceEncrypted = _a[1];
41
44
  var _b = nonceEncrypted.split(':').map(tweetnacl_util_1.decodeBase64), nonce = _b[0], encrypted = _b[1];
42
- return tweetnacl_1.default.box.open(encrypted, nonce, tweetnacl_util_1.decodeBase64(submissionPublicKey), tweetnacl_util_1.decodeBase64(formPrivateKey));
45
+ return tweetnacl_1.default.box.open(encrypted, nonce, (0, tweetnacl_util_1.decodeBase64)(submissionPublicKey), (0, tweetnacl_util_1.decodeBase64)(formPrivateKey));
43
46
  }
44
47
  catch (err) {
45
48
  return null;
46
49
  }
47
50
  };
51
+ exports.decryptContent = decryptContent;
48
52
  /**
49
53
  * Helper method to verify a signed message.
50
54
  * @param msg the message to verify
@@ -52,28 +56,31 @@ exports.decryptContent = function (formPrivateKey, encryptedContent) {
52
56
  * @returns the signed message if successful, else an error will be thrown
53
57
  * @throws {Error} if the message cannot be verified
54
58
  */
55
- exports.verifySignedMessage = function (msg, publicKey) {
56
- var openedMessage = tweetnacl_1.default.sign.open(msg, tweetnacl_util_1.decodeBase64(publicKey));
59
+ var verifySignedMessage = function (msg, publicKey) {
60
+ var openedMessage = tweetnacl_1.default.sign.open(msg, (0, tweetnacl_util_1.decodeBase64)(publicKey));
57
61
  if (!openedMessage)
58
62
  throw new Error('Failed to open signed message with given public key');
59
- return JSON.parse(tweetnacl_util_1.encodeUTF8(openedMessage));
63
+ return JSON.parse((0, tweetnacl_util_1.encodeUTF8)(openedMessage));
60
64
  };
65
+ exports.verifySignedMessage = verifySignedMessage;
61
66
  /**
62
67
  * Helper method to check if all the field IDs given are within the filenames
63
68
  * @param fieldIds the list of fieldIds to check
64
69
  * @param filenames the filenames that should contain the fields
65
70
  * @returns boolean indicating whether the fields are valid
66
71
  */
67
- exports.areAttachmentFieldIdsValid = function (fieldIds, filenames) {
72
+ var areAttachmentFieldIdsValid = function (fieldIds, filenames) {
68
73
  return fieldIds.every(function (fieldId) { return filenames[fieldId]; });
69
74
  };
75
+ exports.areAttachmentFieldIdsValid = areAttachmentFieldIdsValid;
70
76
  /**
71
77
  * Converts an encrypted attachment to encrypted file content
72
78
  * @param encryptedAttachment The encrypted attachment
73
79
  * @returns EncryptedFileContent The encrypted file content
74
80
  */
75
- exports.convertEncryptedAttachmentToFileContent = function (encryptedAttachment) { return ({
81
+ var convertEncryptedAttachmentToFileContent = function (encryptedAttachment) { return ({
76
82
  submissionPublicKey: encryptedAttachment.encryptedFile.submissionPublicKey,
77
83
  nonce: encryptedAttachment.encryptedFile.nonce,
78
- binary: tweetnacl_util_1.decodeBase64(encryptedAttachment.encryptedFile.binary),
84
+ binary: (0, tweetnacl_util_1.decodeBase64)(encryptedAttachment.encryptedFile.binary),
79
85
  }); };
86
+ exports.convertEncryptedAttachmentToFileContent = convertEncryptedAttachmentToFileContent;
@@ -1,10 +1,10 @@
1
- export declare type HeaderSignature = {
1
+ export type HeaderSignature = {
2
2
  v1: string;
3
3
  t: number;
4
4
  s: string;
5
5
  f: string;
6
6
  };
7
- export declare type VerificationSignature = {
7
+ export type VerificationSignature = {
8
8
  v: string;
9
9
  t: number;
10
10
  s: string;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseVerificationSignature = exports.parseSignatureHeader = void 0;
3
4
  /**
4
5
  * Helper function to retrieve keys-values in a signature.
5
6
  * @param signature The signature to convert to a keymap
@@ -20,18 +21,20 @@ var signatureToKeyMap = function (signature) {
20
21
  * @param header The X-FormSG-Signature header
21
22
  * @returns The signature header constituents
22
23
  */
23
- exports.parseSignatureHeader = function (header) {
24
+ var parseSignatureHeader = function (header) {
24
25
  var parsedSignature = signatureToKeyMap(header);
25
26
  parsedSignature.t = Number(parsedSignature.t);
26
27
  return parsedSignature;
27
28
  };
29
+ exports.parseSignatureHeader = parseSignatureHeader;
28
30
  /**
29
31
  * Parses the verification signature into its constituent
30
32
  * @param signature The verification signature
31
33
  * @returns The verification signature constituents
32
34
  */
33
- exports.parseVerificationSignature = function (signature) {
35
+ var parseVerificationSignature = function (signature) {
34
36
  var parsedSignature = signatureToKeyMap(signature);
35
37
  parsedSignature.t = Number(parsedSignature.t);
36
38
  return parsedSignature;
37
39
  };
40
+ exports.parseVerificationSignature = parseVerificationSignature;
@@ -3,6 +3,7 @@ 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.getVerificationPublicKey = exports.getSigningPublicKey = void 0;
6
7
  var signing_keys_1 = require("../resource/signing-keys");
7
8
  var verification_keys_1 = require("../resource/verification-keys");
8
9
  var stage_1 = __importDefault(require("./stage"));
@@ -1,12 +1,29 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
2
18
  var __importStar = (this && this.__importStar) || function (mod) {
3
19
  if (mod && mod.__esModule) return mod;
4
20
  var result = {};
5
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
6
- result["default"] = mod;
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
7
23
  return result;
8
24
  };
9
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.verify = exports.sign = void 0;
10
27
  var tweetnacl = __importStar(require("tweetnacl"));
11
28
  var tweetnacl_util_1 = require("tweetnacl-util");
12
29
  /**
@@ -16,7 +33,7 @@ var tweetnacl_util_1 = require("tweetnacl-util");
16
33
  * @return base64 encoded signature
17
34
  */
18
35
  function sign(basestring, secretKey) {
19
- return tweetnacl_util_1.encodeBase64(tweetnacl.sign.detached(tweetnacl_util_1.decodeUTF8(basestring), tweetnacl_util_1.decodeBase64(secretKey)));
36
+ return (0, tweetnacl_util_1.encodeBase64)(tweetnacl.sign.detached((0, tweetnacl_util_1.decodeUTF8)(basestring), (0, tweetnacl_util_1.decodeBase64)(secretKey)));
20
37
  }
21
38
  exports.sign = sign;
22
39
  /**
@@ -27,6 +44,6 @@ exports.sign = sign;
27
44
  * @return True if verification checks out, false otherwise
28
45
  */
29
46
  function verify(message, signature, publicKey) {
30
- return tweetnacl.sign.detached.verify(tweetnacl_util_1.decodeUTF8(message), tweetnacl_util_1.decodeBase64(signature), tweetnacl_util_1.decodeBase64(publicKey));
47
+ return tweetnacl.sign.detached.verify((0, tweetnacl_util_1.decodeUTF8)(message), (0, tweetnacl_util_1.decodeBase64)(signature), (0, tweetnacl_util_1.decodeBase64)(publicKey));
31
48
  }
32
49
  exports.verify = verify;
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.determineIsFormFields = void 0;
3
4
  function determineIsFormFields(tbd) {
4
5
  if (!Array.isArray(tbd)) {
5
6
  return false;
@@ -14,7 +15,9 @@ function determineIsFormFields(tbd) {
14
15
  internal.isHeader) &&
15
16
  internal._id &&
16
17
  internal.fieldType &&
17
- internal.question;
18
+ // The field is still valid even when the question title is empty string
19
+ // (even though it is not intended behavior).
20
+ typeof internal.question === 'string';
18
21
  });
19
22
  return filter.length === tbd.length;
20
23
  }
@@ -1,12 +1,29 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
2
18
  var __importStar = (this && this.__importStar) || function (mod) {
3
19
  if (mod && mod.__esModule) return mod;
4
20
  var result = {};
5
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
6
- result["default"] = mod;
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
7
23
  return result;
8
24
  };
9
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
+ exports.hasEpochExpired = exports.isSignatureHeaderValid = void 0;
10
27
  var url = __importStar(require("url"));
11
28
  var errors_1 = require("../errors");
12
29
  var signature_1 = require("./signature");
@@ -23,8 +40,8 @@ var isSignatureHeaderValid = function (uri, signatureHeader, publicKey) {
23
40
  if (!epoch || !signature || !submissionId || !formId) {
24
41
  throw new errors_1.WebhookAuthenticateError('X-FormSG-Signature header is invalid');
25
42
  }
26
- var baseString = url.parse(uri).href + "." + submissionId + "." + formId + "." + epoch;
27
- return signature_1.verify(baseString, signature, publicKey);
43
+ var baseString = "".concat(url.parse(uri).href, ".").concat(submissionId, ".").concat(formId, ".").concat(epoch);
44
+ return (0, signature_1.verify)(baseString, signature, publicKey);
28
45
  };
29
46
  exports.isSignatureHeaderValid = isSignatureHeaderValid;
30
47
  /**
@@ -33,27 +33,27 @@ var Verification = /** @class */ (function () {
33
33
  throw new errors_1.MissingPublicKeyError();
34
34
  }
35
35
  try {
36
- var _b = parser_1.parseVerificationSignature(signatureString), transactionId = _b.v, time = _b.t, formId = _b.f, signature = _b.s;
36
+ var _b = (0, parser_1.parseVerificationSignature)(signatureString), transactionId = _b.v, time = _b.t, formId = _b.f, signature = _b.s;
37
37
  if (!time) {
38
38
  throw new Error('Malformed signature string was passed into function');
39
39
  }
40
- if (utils_1.isSignatureTimeValid(time, submissionCreatedAt, _this.transactionExpiry)) {
41
- var data = utils_1.formatToBaseString({
40
+ if ((0, utils_1.isSignatureTimeValid)(time, submissionCreatedAt, _this.transactionExpiry)) {
41
+ var data = (0, utils_1.formatToBaseString)({
42
42
  transactionId: transactionId,
43
43
  formId: formId,
44
44
  fieldId: fieldId,
45
45
  answer: answer,
46
46
  time: time,
47
47
  });
48
- return tweetnacl_1.default.sign.detached.verify(tweetnacl_util_1.decodeUTF8(data), tweetnacl_util_1.decodeBase64(signature), tweetnacl_util_1.decodeBase64(_this.verificationPublicKey));
48
+ return tweetnacl_1.default.sign.detached.verify((0, tweetnacl_util_1.decodeUTF8)(data), (0, tweetnacl_util_1.decodeBase64)(signature), (0, tweetnacl_util_1.decodeBase64)(_this.verificationPublicKey));
49
49
  }
50
50
  else {
51
- console.info("Signature was expired for signatureString=\"" + signatureString + "\" signatureDate=\"" + time + "\" submissionCreatedAt=\"" + submissionCreatedAt + "\"");
51
+ console.info("Signature was expired for signatureString=\"".concat(signatureString, "\" signatureDate=\"").concat(time, "\" submissionCreatedAt=\"").concat(submissionCreatedAt, "\""));
52
52
  return false;
53
53
  }
54
54
  }
55
55
  catch (error) {
56
- console.error("An error occurred for signatureString=\"" + signatureString + "\" submissionCreatedAt=\"" + submissionCreatedAt + "\" fieldId=\"" + fieldId + "\" answer=\"" + answer + "\" error=\"" + error + "\"");
56
+ console.error("An error occurred for signatureString=\"".concat(signatureString, "\" submissionCreatedAt=\"").concat(submissionCreatedAt, "\" fieldId=\"").concat(fieldId, "\" answer=\"").concat(answer, "\" error=\"").concat(error, "\""));
57
57
  return false;
58
58
  }
59
59
  };
@@ -63,15 +63,15 @@ var Verification = /** @class */ (function () {
63
63
  throw new errors_1.MissingSecretKeyError('Provide a secret key when when initializing the Verification class to use this function.');
64
64
  }
65
65
  var time = Date.now();
66
- var data = utils_1.formatToBaseString({
66
+ var data = (0, utils_1.formatToBaseString)({
67
67
  transactionId: transactionId,
68
68
  formId: formId,
69
69
  fieldId: fieldId,
70
70
  answer: answer,
71
71
  time: time,
72
72
  });
73
- var signature = tweetnacl_1.default.sign.detached(tweetnacl_util_1.decodeUTF8(data), tweetnacl_util_1.decodeBase64(_this.verificationSecretKey));
74
- return "f=" + formId + ",v=" + transactionId + ",t=" + time + ",s=" + tweetnacl_util_1.encodeBase64(signature);
73
+ var signature = tweetnacl_1.default.sign.detached((0, tweetnacl_util_1.decodeUTF8)(data), (0, tweetnacl_util_1.decodeBase64)(_this.verificationSecretKey));
74
+ return "f=".concat(formId, ",v=").concat(transactionId, ",t=").concat(time, ",s=").concat((0, tweetnacl_util_1.encodeBase64)(signature));
75
75
  };
76
76
  this.verificationPublicKey = params === null || params === void 0 ? void 0 : params.publicKey;
77
77
  this.verificationSecretKey = params === null || params === void 0 ? void 0 : params.secretKey;
@@ -1,20 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.formatToBaseString = exports.isSignatureTimeValid = void 0;
3
4
  /**
4
5
  * Checks if signature was made within the given expiry range before
5
6
  * submission was created.
6
7
  * @param signatureTime ms
7
8
  * @param submissionCreatedAt ms
8
9
  */
9
- exports.isSignatureTimeValid = function (signatureTime, submissionCreatedAt, transactionExpiry) {
10
+ var isSignatureTimeValid = function (signatureTime, submissionCreatedAt, transactionExpiry) {
10
11
  var maxTime = submissionCreatedAt;
11
12
  var minTime = maxTime - transactionExpiry * 1000;
12
13
  return signatureTime > minTime && signatureTime < maxTime;
13
14
  };
15
+ exports.isSignatureTimeValid = isSignatureTimeValid;
14
16
  /**
15
17
  * Formats given data into a string for signing
16
18
  */
17
- exports.formatToBaseString = function (_a) {
19
+ var formatToBaseString = function (_a) {
18
20
  var transactionId = _a.transactionId, formId = _a.formId, fieldId = _a.fieldId, answer = _a.answer, time = _a.time;
19
- return transactionId + "." + formId + "." + fieldId + "." + answer + "." + time;
21
+ return "".concat(transactionId, ".").concat(formId, ".").concat(fieldId, ".").concat(answer, ".").concat(time);
20
22
  };
23
+ exports.formatToBaseString = formatToBaseString;
package/dist/webhooks.js CHANGED
@@ -1,9 +1,25 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
2
18
  var __importStar = (this && this.__importStar) || function (mod) {
3
19
  if (mod && mod.__esModule) return mod;
4
20
  var result = {};
5
- if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
6
- result["default"] = mod;
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
7
23
  return result;
8
24
  };
9
25
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -14,8 +30,8 @@ var webhooks_1 = require("./util/webhooks");
14
30
  var errors_1 = require("./errors");
15
31
  var Webhooks = /** @class */ (function () {
16
32
  function Webhooks(_a) {
17
- var _this = this;
18
33
  var publicKey = _a.publicKey, secretKey = _a.secretKey;
34
+ var _this = this;
19
35
  /**
20
36
  * Injects the webhook public key for authentication
21
37
  * @param header X-FormSG-Signature header
@@ -25,15 +41,15 @@ var Webhooks = /** @class */ (function () {
25
41
  */
26
42
  this.authenticate = function (header, uri) {
27
43
  // Parse the header
28
- var signatureHeader = parser_1.parseSignatureHeader(header);
44
+ var signatureHeader = (0, parser_1.parseSignatureHeader)(header);
29
45
  var signature = signatureHeader.v1, epoch = signatureHeader.t, submissionId = signatureHeader.s, formId = signatureHeader.f;
30
46
  // Verify signature authenticity
31
- if (!webhooks_1.isSignatureHeaderValid(uri, signatureHeader, _this.publicKey)) {
32
- throw new errors_1.WebhookAuthenticateError("Signature could not be verified for uri=" + uri + " submissionId=" + submissionId + " formId=" + formId + " epoch=" + epoch + " signature=" + signature);
47
+ if (!(0, webhooks_1.isSignatureHeaderValid)(uri, signatureHeader, _this.publicKey)) {
48
+ throw new errors_1.WebhookAuthenticateError("Signature could not be verified for uri=".concat(uri, " submissionId=").concat(submissionId, " formId=").concat(formId, " epoch=").concat(epoch, " signature=").concat(signature));
33
49
  }
34
50
  // Verify epoch recency
35
- if (webhooks_1.hasEpochExpired(epoch)) {
36
- throw new errors_1.WebhookAuthenticateError("Signature is not recent for uri=" + uri + " submissionId=" + submissionId + " formId=" + formId + " epoch=" + epoch + " signature=" + signature);
51
+ if ((0, webhooks_1.hasEpochExpired)(epoch)) {
52
+ throw new errors_1.WebhookAuthenticateError("Signature is not recent for uri=".concat(uri, " submissionId=").concat(submissionId, " formId=").concat(formId, " epoch=").concat(epoch, " signature=").concat(signature));
37
53
  }
38
54
  // All checks pass.
39
55
  return true;
@@ -56,8 +72,8 @@ var Webhooks = /** @class */ (function () {
56
72
  if (!submissionId || !uri || !formId || !epoch) {
57
73
  throw new TypeError('submissionId, uri, formId, or epoch must be provided to generate a webhook signature');
58
74
  }
59
- var baseString = url.parse(uri).href + "." + submissionId + "." + formId + "." + epoch;
60
- return signature_1.sign(baseString, _this.secretKey);
75
+ var baseString = "".concat(url.parse(uri).href, ".").concat(submissionId, ".").concat(formId, ".").concat(epoch);
76
+ return (0, signature_1.sign)(baseString, _this.secretKey);
61
77
  };
62
78
  /**
63
79
  * Constructs the `X-FormSG-Signature` header
@@ -74,7 +90,7 @@ var Webhooks = /** @class */ (function () {
74
90
  if (!_this.secretKey) {
75
91
  throw new errors_1.MissingSecretKeyError();
76
92
  }
77
- return "t=" + epoch + ",s=" + submissionId + ",f=" + formId + ",v1=" + signature;
93
+ return "t=".concat(epoch, ",s=").concat(submissionId, ",f=").concat(formId, ",v1=").concat(signature);
78
94
  };
79
95
  this.publicKey = publicKey;
80
96
  this.secretKey = secretKey;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opengovsg/formsg-sdk",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/opengovsg/formsg-javascript-sdk.git"
@@ -13,7 +13,8 @@
13
13
  "test-ci": "jest --coverage",
14
14
  "test-watch": "jest --watch",
15
15
  "build": "tsc",
16
- "prepare": "npm run build"
16
+ "prepare": "npm run build",
17
+ "version": "auto-changelog -p && git add CHANGELOG.md"
17
18
  },
18
19
  "keywords": [
19
20
  "formsg",
@@ -23,7 +24,7 @@
23
24
  "author": "Open Government Products (FormSG)",
24
25
  "license": "MIT",
25
26
  "dependencies": {
26
- "axios": "^0.21.1",
27
+ "axios": "^1.6.2",
27
28
  "tweetnacl": "^1.0.3",
28
29
  "tweetnacl-util": "^0.15.1"
29
30
  },
@@ -31,19 +32,20 @@
31
32
  "@babel/cli": "^7.8.4",
32
33
  "@babel/core": "^7.9.0",
33
34
  "@babel/preset-env": "^7.9.0",
34
- "@types/jest": "^25.2.1",
35
- "@types/node": "^13.11.1",
35
+ "@types/jest": "^29.5.8",
36
+ "@types/node": "^18.18.9",
36
37
  "@typescript-eslint/eslint-plugin": "^4.25.0",
37
- "coveralls": "^3.1.0",
38
+ "auto-changelog": "^2.4.0",
39
+ "coveralls": "^3.1.1",
38
40
  "eslint-config-prettier": "^8.3.0",
39
41
  "eslint-plugin-import": "^2.23.3",
40
42
  "eslint-plugin-jest": "^24.3.6",
41
43
  "eslint-plugin-prettier": "^3.4.0",
42
44
  "eslint-plugin-simple-import-sort": "^7.0.0",
43
45
  "eslint-plugin-typesafe": "^0.5.2",
44
- "jest": "^25.3.0",
45
- "jest-mock-axios": "^4.4.0",
46
- "ts-jest": "^25.3.1",
47
- "typescript": "^3.8.3"
46
+ "jest": "^29.7.0",
47
+ "jest-mock-axios": "^4.7.3",
48
+ "ts-jest": "^29.1.1",
49
+ "typescript": "^4.9.5"
48
50
  }
49
51
  }