dce-reactkit 3.12.1-beta-cross-server.1 → 3.12.1-beta-cross-server.3

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.
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Sign data with a private reactkit key, package it into a signed data pack
2
+ * Sign a request and get the new request params
3
3
  * @author Gabe Abrams
4
4
  * @param opts object containing all arguments
5
5
  * @param opts.method the method to sign
@@ -7,9 +7,9 @@
7
7
  * @param opts.params the data in the body to sign
8
8
  * @param opts.key the reactkit key to sign with
9
9
  * @param opts.secret the reactkit secret to sign with
10
- * @return the signed data
10
+ * @return augmented params for the request, including a signature, timestamp, and key
11
11
  */
12
- export declare const createSignedPack: (opts: {
12
+ export declare const signRequest: (opts: {
13
13
  method: string;
14
14
  path: string;
15
15
  params: {
@@ -17,22 +17,24 @@ export declare const createSignedPack: (opts: {
17
17
  };
18
18
  key: string;
19
19
  secret: string;
20
- }) => string;
20
+ }) => Promise<{
21
+ [key: string]: any;
22
+ }>;
21
23
  /**
22
- * Parse signed pack. Throws an error if invalid
24
+ * Validate a signed request. Throws an error if invalid
23
25
  * @author Gabe Abrams
24
26
  * @param opts object containing all arguments
25
27
  * @param opts.method the method of the data validate
26
28
  * @param opts.path the http request path to validate
27
29
  * @param opts.scope the name of the scope to validate
28
- * @param opts.signedPack the signed data pack to validate
30
+ * @param opts.params the request data to validate
29
31
  * @returns parsed and validated params
30
32
  */
31
- export declare const parseSignedPack: (opts: {
33
+ export declare const validateSignedRequest: (opts: {
32
34
  method: string;
33
35
  path: string;
34
36
  scope: string;
35
- signedPack: string;
36
- }) => Promise<{
37
- [key: string]: any;
38
- }>;
37
+ params: {
38
+ [key: string]: any;
39
+ };
40
+ }) => Promise<void>;
@@ -5,10 +5,6 @@
5
5
  * @param opts.method the method of the endpoint
6
6
  * @param opts.path the path of the other server's endpoint
7
7
  * @param opts.host the host of the other server
8
- * @param [opts.key=process.env.REACTKIT_CROSS_SERVER_CREDENTIAL_KEY] reactkit cross-server
9
- * credential key
10
- * @param [opts.secret=process.env.REACTKIT_CROSS_SERVER_CREDENTIAL_SECRET reactkit cross-server
11
- * credential secret
12
8
  * @param [opts.params={}] query/body parameters to include
13
9
  * @param [opts.responseType=JSON] the response type from the other server
14
10
  */
@@ -16,8 +12,6 @@ declare const visitEndpointOnAnotherServer: (opts: {
16
12
  method: 'GET' | 'POST' | 'DELETE' | 'PUT';
17
13
  path: string;
18
14
  host: string;
19
- key?: string | undefined;
20
- secret?: string | undefined;
21
15
  params?: {
22
16
  [x: string]: any;
23
17
  } | undefined;
@@ -54,6 +54,7 @@ import onlyKeepLetters from './helpers/onlyKeepLetters';
54
54
  import parallelLimit from './helpers/parallelLimit';
55
55
  import logClientEvent, { setClientEventMetadataPopulator } from './helpers/logClientEvent';
56
56
  import initLogCollection from './server/initLogCollection';
57
+ import initCrossServerCredentialCollection from './server/initCrossServerCredentialCollection';
57
58
  import getMonthName from './helpers/getMonthName';
58
59
  import genCSV from './helpers/genCSV';
59
60
  import canReviewLogs from './helpers/canReviewLogs';
@@ -100,4 +101,4 @@ import PickableItem from './components/ItemPicker/types/PickableItem';
100
101
  import DBEntry from './components/DBEntryManagerPanel/types/DBEntry';
101
102
  import DBEntryField from './components/DBEntryManagerPanel/types/DBEntryField';
102
103
  import DBEntryFieldType from './components/DBEntryManagerPanel/types/DBEntryFieldType';
103
- export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, LogReviewer, IntelliTable, CSVDownloadButton, DBEntryManagerPanel, Tooltip, ToggleSwitch, AutoscrollToBottomContainer, MultiSwitch, Dropdown, alert, prompt, confirm, showFatalError, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, DynamicWord, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, stubServerEndpoint, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, getMonthName, genCSV, canReviewLogs, isMobileOrTablet, extractProp, compareArraysByProp, genCommaList, validateEmail, validatePhoneNumber, validateString, getLocalTimeInfo, idify, makeLinksClickable, prefixWithAOrAn, everyAsync, filterAsync, forEachAsync, mapAsync, someAsync, capitalize, shuffleArray, initClient, visitServerEndpoint, logClientEvent, addFatalErrorHandler, leaveToURL, combineClassNames, useForceRender, setClientEventMetadataPopulator, initServer, genRouteHandler, handleError, handleSuccess, initLogCollection, addDBEditorEndpoints, visitEndpointOnAnotherServer, ModalButtonType, ModalSize, ModalType, ReactKitErrorCode, Variant, DayOfWeek, Log, LogType, LogSource, LogAction, LogBuiltInMetadata, LogMetadataType, LogFunction, IntelliTableColumn, DropdownItemType, CrossServerCredential, PickableItem, DBEntry, DBEntryField, DBEntryFieldType, ParamType, };
104
+ export { AppWrapper, LoadingSpinner, ErrorBox, Modal, TabBox, RadioButton, CheckboxButton, ButtonInputGroup, SimpleDateChooser, Drawer, PopSuccessMark, PopFailureMark, PopPendingMark, CopiableBox, ItemPicker, LogReviewer, IntelliTable, CSVDownloadButton, DBEntryManagerPanel, Tooltip, ToggleSwitch, AutoscrollToBottomContainer, MultiSwitch, Dropdown, alert, prompt, confirm, showFatalError, ErrorWithCode, MINUTE_IN_MS, HOUR_IN_MS, DAY_IN_MS, DynamicWord, abbreviate, avg, ceilToNumDecimals, floorToNumDecimals, forceNumIntoBounds, padDecimalZeros, padZerosLeft, roundToNumDecimals, sum, waitMs, getOrdinal, getTimeInfoInET, stubServerEndpoint, startMinWait, getHumanReadableDate, getPartOfDay, stringsToHumanReadableList, onlyKeepLetters, parallelLimit, getMonthName, genCSV, canReviewLogs, isMobileOrTablet, extractProp, compareArraysByProp, genCommaList, validateEmail, validatePhoneNumber, validateString, getLocalTimeInfo, idify, makeLinksClickable, prefixWithAOrAn, everyAsync, filterAsync, forEachAsync, mapAsync, someAsync, capitalize, shuffleArray, initClient, visitServerEndpoint, logClientEvent, addFatalErrorHandler, leaveToURL, combineClassNames, useForceRender, setClientEventMetadataPopulator, initServer, genRouteHandler, handleError, handleSuccess, initLogCollection, initCrossServerCredentialCollection, addDBEditorEndpoints, visitEndpointOnAnotherServer, ModalButtonType, ModalSize, ModalType, ReactKitErrorCode, Variant, DayOfWeek, Log, LogType, LogSource, LogAction, LogBuiltInMetadata, LogMetadataType, LogFunction, IntelliTableColumn, DropdownItemType, CrossServerCredential, PickableItem, DBEntry, DBEntryField, DBEntryFieldType, ParamType, };
@@ -21,17 +21,19 @@ declare enum ReactKitErrorCode {
21
21
  NotConnected = "DRK14",
22
22
  SelfSigned = "DRK15",
23
23
  ResponseParseError = "DRK16",
24
- PackUnparseable = "DRK28",
25
- PackInvalidMethod = "DRK19",
26
- PackInvalidPath = "DRK20",
27
- PackInvalidCollection = "DRK21",
28
- PackInvalidCredential = "DRK23",
29
- PackInvalidScope = "DRK22",
30
- PackInvalidTimestamp = "DRK24",
31
- PackInvalidSignature = "DRK25",
32
- PackInvalidBody = "DRK26",
24
+ SignedRequestUnparseable = "DRK28",
25
+ SignedRequestInvalidCollection = "DRK21",
26
+ SignedRequestInvalidCredential = "DRK23",
27
+ SignedRequestInvalidScope = "DRK22",
28
+ SignedRequestInvalidTimestamp = "DRK24",
29
+ SignedRequestInvalidSignature = "DRK25",
30
+ SignedRequestInvalidBody = "DRK26",
33
31
  CrossServerNoCredentialsToSignWith = "DRK27",
34
- CrossServerNoPack = "DRK29",
35
- CrossServerNoCredentialEncodingSalt = "DRK30"
32
+ CrossServerMissingSignedRequestInfo = "DRK29",
33
+ CrossServerNoCredentialEncodingSalt = "DRK30",
34
+ NoOauthLib = "DRK31",
35
+ NoCryptoLib = "DRK32",
36
+ InvalidCrossServerCredentialsFormat = "DRK33",
37
+ UnknownCrossServerError = "DRK34"
36
38
  }
37
39
  export default ReactKitErrorCode;
package/dist/index.d.ts CHANGED
@@ -1339,6 +1339,14 @@ declare const logClientEvent: LogFunction;
1339
1339
  */
1340
1340
  declare const initLogCollection: (Collection: any) => any;
1341
1341
 
1342
+ /**
1343
+ * Initialize a cross-server credential collection given the dce-mango Collection class
1344
+ * @author Gabe Abrams
1345
+ * @param Collection the Collection class from dce-mango
1346
+ * @returns initialized logCollection
1347
+ */
1348
+ declare const initCrossServerCredentialCollection: (Collection: any) => any;
1349
+
1342
1350
  /**
1343
1351
  * Get the name of a month given the month number (1 = January, etc.)
1344
1352
  * If an invalid number is provided, we will treat it like January
@@ -1666,10 +1674,6 @@ declare const shuffleArray: <T>(arr: T[]) => T[];
1666
1674
  * @param opts.method the method of the endpoint
1667
1675
  * @param opts.path the path of the other server's endpoint
1668
1676
  * @param opts.host the host of the other server
1669
- * @param [opts.key=process.env.REACTKIT_CROSS_SERVER_CREDENTIAL_KEY] reactkit cross-server
1670
- * credential key
1671
- * @param [opts.secret=process.env.REACTKIT_CROSS_SERVER_CREDENTIAL_SECRET reactkit cross-server
1672
- * credential secret
1673
1677
  * @param [opts.params={}] query/body parameters to include
1674
1678
  * @param [opts.responseType=JSON] the response type from the other server
1675
1679
  */
@@ -1677,8 +1681,6 @@ declare const visitEndpointOnAnotherServer: (opts: {
1677
1681
  method: 'GET' | 'POST' | 'DELETE' | 'PUT';
1678
1682
  path: string;
1679
1683
  host: string;
1680
- key?: string | undefined;
1681
- secret?: string | undefined;
1682
1684
  params?: {
1683
1685
  [x: string]: any;
1684
1686
  } | undefined;
@@ -1708,18 +1710,20 @@ declare enum ReactKitErrorCode {
1708
1710
  NotConnected = "DRK14",
1709
1711
  SelfSigned = "DRK15",
1710
1712
  ResponseParseError = "DRK16",
1711
- PackUnparseable = "DRK28",
1712
- PackInvalidMethod = "DRK19",
1713
- PackInvalidPath = "DRK20",
1714
- PackInvalidCollection = "DRK21",
1715
- PackInvalidCredential = "DRK23",
1716
- PackInvalidScope = "DRK22",
1717
- PackInvalidTimestamp = "DRK24",
1718
- PackInvalidSignature = "DRK25",
1719
- PackInvalidBody = "DRK26",
1713
+ SignedRequestUnparseable = "DRK28",
1714
+ SignedRequestInvalidCollection = "DRK21",
1715
+ SignedRequestInvalidCredential = "DRK23",
1716
+ SignedRequestInvalidScope = "DRK22",
1717
+ SignedRequestInvalidTimestamp = "DRK24",
1718
+ SignedRequestInvalidSignature = "DRK25",
1719
+ SignedRequestInvalidBody = "DRK26",
1720
1720
  CrossServerNoCredentialsToSignWith = "DRK27",
1721
- CrossServerNoPack = "DRK29",
1722
- CrossServerNoCredentialEncodingSalt = "DRK30"
1721
+ CrossServerMissingSignedRequestInfo = "DRK29",
1722
+ CrossServerNoCredentialEncodingSalt = "DRK30",
1723
+ NoOauthLib = "DRK31",
1724
+ NoCryptoLib = "DRK32",
1725
+ InvalidCrossServerCredentialsFormat = "DRK33",
1726
+ UnknownCrossServerError = "DRK34"
1723
1727
  }
1724
1728
 
1725
1729
  /**
@@ -1763,4 +1767,4 @@ type CrossServerCredential = {
1763
1767
  scopes: string[];
1764
1768
  };
1765
1769
 
1766
- export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, CrossServerCredential, DAY_IN_MS, DBEntry, DBEntryField, DBEntryFieldType, DBEntryManagerPanel, DayOfWeek, Drawer, Dropdown, DropdownItemType, DynamicWord, ErrorBox, ErrorWithCode, HOUR_IN_MS, IntelliTable, IntelliTableColumn, ItemPicker, LoadingSpinner, Log, LogAction, LogBuiltInMetadata, LogFunction, LogMetadataType, LogReviewer, LogSource, LogType, MINUTE_IN_MS, Modal, ModalButtonType, ModalSize, ModalType, MultiSwitch, ParamType, PickableItem, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert, avg, canReviewLogs, capitalize, ceilToNumDecimals, combineClassNames, compareArraysByProp, confirm, everyAsync, extractProp, filterAsync, floorToNumDecimals, forEachAsync, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, idify, initClient, initLogCollection, initServer, isMobileOrTablet, leaveToURL, logClientEvent, makeLinksClickable, mapAsync, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, prefixWithAOrAn, prompt, roundToNumDecimals, setClientEventMetadataPopulator, showFatalError, shuffleArray, someAsync, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, useForceRender, validateEmail, validatePhoneNumber, validateString, visitEndpointOnAnotherServer, visitServerEndpoint, waitMs };
1770
+ export { AppWrapper, AutoscrollToBottomContainer, ButtonInputGroup, CSVDownloadButton, CheckboxButton, CopiableBox, CrossServerCredential, DAY_IN_MS, DBEntry, DBEntryField, DBEntryFieldType, DBEntryManagerPanel, DayOfWeek, Drawer, Dropdown, DropdownItemType, DynamicWord, ErrorBox, ErrorWithCode, HOUR_IN_MS, IntelliTable, IntelliTableColumn, ItemPicker, LoadingSpinner, Log, LogAction, LogBuiltInMetadata, LogFunction, LogMetadataType, LogReviewer, LogSource, LogType, MINUTE_IN_MS, Modal, ModalButtonType, ModalSize, ModalType, MultiSwitch, ParamType, PickableItem, PopFailureMark, PopPendingMark, PopSuccessMark, RadioButton, ReactKitErrorCode, SimpleDateChooser, TabBox, ToggleSwitch, Tooltip, Variant, abbreviate, addDBEditorEndpoints, addFatalErrorHandler, alert, avg, canReviewLogs, capitalize, ceilToNumDecimals, combineClassNames, compareArraysByProp, confirm, everyAsync, extractProp, filterAsync, floorToNumDecimals, forEachAsync, forceNumIntoBounds, genCSV, genCommaList, genRouteHandler, getHumanReadableDate, getLocalTimeInfo, getMonthName, getOrdinal, getPartOfDay, getTimeInfoInET, handleError, handleSuccess, idify, initClient, initCrossServerCredentialCollection, initLogCollection, initServer, isMobileOrTablet, leaveToURL, logClientEvent, makeLinksClickable, mapAsync, onlyKeepLetters, padDecimalZeros, padZerosLeft, parallelLimit, prefixWithAOrAn, prompt, roundToNumDecimals, setClientEventMetadataPopulator, showFatalError, shuffleArray, someAsync, startMinWait, stringsToHumanReadableList, stubServerEndpoint, sum, useForceRender, validateEmail, validatePhoneNumber, validateString, visitEndpointOnAnotherServer, visitServerEndpoint, waitMs };
@@ -1,13 +1,26 @@
1
- // Import jwt
2
- import jwt from 'jwt-simple';
1
+ // Import crypto
2
+ import crypto from 'crypto';
3
+
4
+ const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
3
5
 
4
6
  // Get args
5
- let { REACTKIT_CRED_ENCODING_SALT } = process.env;
7
+ const REACTKIT_CRED_ENCODING_SALT = process.env.npm_config_salt;
6
8
  if (!REACTKIT_CRED_ENCODING_SALT) {
7
- REACTKIT_CRED_ENCODING_SALT = process.env.npm_config_salt;
9
+ console.log('Encoding salt is required: --salt=...');
10
+ process.exit(1);
8
11
  }
9
- if (!REACTKIT_CRED_ENCODING_SALT) {
10
- console.log('REACTKIT_CRED_ENCODING_SALT is required either as an environment variable or as: --salt=...');
12
+
13
+ // Get the key
14
+ let key = process.env.npm_config_key;
15
+ if (!key) {
16
+ console.log('Key is required: --key=...');
17
+ process.exit(1);
18
+ }
19
+
20
+ // Get the description
21
+ let description = process.env.npm_config_description;
22
+ if (!description) {
23
+ console.log('Description is required: --description=...');
11
24
  process.exit(1);
12
25
  }
13
26
 
@@ -15,14 +28,57 @@ if (!REACTKIT_CRED_ENCODING_SALT) {
15
28
  let secret = process.env.npm_config_secret;
16
29
  if (!secret) {
17
30
  // Generate a random secret
18
- const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
19
31
  secret = '';
20
- for (let i = 0; i < 64; i++) {
32
+ for (let i = 0; i < 32; i++) {
21
33
  secret += chars.charAt(Math.floor(Math.random() * chars.length));
22
34
  }
23
35
  console.log('Generated a random secret. If you have one in mind, use --secret=...');
24
36
  }
25
37
 
26
- // Encode the secret
27
- const encodedSecret = jwt.encode(secret, REACTKIT_CRED_ENCODING_SALT);
28
- console.log(`\nNew Secret Generated!\n\nSecret: ${secret}\n\nEncoded Secret: ${encodedSecret}`);
38
+ // Get the host name
39
+ const host = process.env.npm_config_host;
40
+ if (!host) {
41
+ console.log('Host of the receiving server is required: --host=...');
42
+ process.exit(1);
43
+ }
44
+
45
+ // Encryption process based on:
46
+ // https://medium.com/@tony.infisical/guide-to-nodes-crypto-module-for-encryption-decryption-65c077176980
47
+
48
+ // Create a random initialization vector
49
+ const iv = crypto.randomBytes(12).toString('base64');
50
+
51
+ // Create a cipher
52
+ const cipher = crypto.createCipheriv(
53
+ 'aes-256-gcm',
54
+ Buffer.from(secret, 'base64'),
55
+ Buffer.from(iv, 'base64'),
56
+ );
57
+
58
+ // Encrypt the string
59
+ let ciphertext = cipher.update(secret, 'utf8', 'base64');
60
+
61
+ // Finalize the encryption
62
+ ciphertext += cipher.final('base64');
63
+
64
+ // Get the authentication tag
65
+ const tag = cipher.getAuthTag();
66
+
67
+ // JSONify the encrypted data
68
+ const encryptionPack = encodeURIComponent(JSON.stringify({
69
+ ciphertext,
70
+ iv,
71
+ tag,
72
+ }));
73
+
74
+ // Show the encrypted data
75
+ console.log('\n\n');
76
+ console.log('––––– Done! What\'s Next: –––––');
77
+ console.log('');
78
+ console.log('On the server *sending* the requests, append the following to the REACTKIT_CROSS_SERVER_CREDENTIALS env var:');
79
+ console.log(`|${host}:${key}:${secret}|`);
80
+ console.log('');
81
+ console.log('On the server *receiving* the requests, add an entry to the "CrossServerCredential" collection:');
82
+ console.log(`{ "description": "${description}", "key": "${key}", "encodedeSecret": "${encryptionPack}", "scopes": [] }`);
83
+ console.log('');
84
+ console.log('For all scopes that the server should have access to, add them to the "scopes" array.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dce-reactkit",
3
- "version": "3.12.1-beta-cross-server.1",
3
+ "version": "3.12.1-beta-cross-server.3",
4
4
  "description": "Shared components for Harvard DCE apps",
5
5
  "main": "dist/cjs/index.js",
6
6
  "module": "dist/esm/index.js",
@@ -25,7 +25,6 @@
25
25
  },
26
26
  "homepage": "https://github.com/harvard-edtech/dce-reactkit#readme",
27
27
  "dependencies": {
28
- "jwt-simple": "^0.5.6",
29
28
  "qs": "^6.x.x",
30
29
  "react-select": "^5.7.3"
31
30
  },
@@ -49,6 +48,7 @@
49
48
  "@types/jest": "^28.1.7",
50
49
  "@types/jwt-simple": "^0.5.36",
51
50
  "@types/node": "^20.2.5",
51
+ "@types/oauth-signature": "^1.5.2",
52
52
  "@types/react": "^17.0.7",
53
53
  "@typescript-eslint/eslint-plugin": "^5.59.9",
54
54
  "@typescript-eslint/parser": "^5.59.9",
@@ -61,6 +61,7 @@
61
61
  "eslint-plugin-react-hooks": "^4.6.0",
62
62
  "jest": "^28.1.3",
63
63
  "jest-environment-jsdom": "^28.1.3",
64
+ "oauth-signature": "^1.5.0",
64
65
  "raixa": "^1.0.21",
65
66
  "rollup": "^2.70.2",
66
67
  "rollup-plugin-dts": "^4.2.1",
package/rollup.config.js CHANGED
@@ -27,6 +27,7 @@ export default [
27
27
  typescript({ tsconfig: "./tsconfig.json" }),
28
28
  sourcemaps(),
29
29
  ],
30
+ inlineDynamicImports: true,
30
31
  external: [
31
32
  ...Object.keys(packageJson.dependencies || {}),
32
33
  ...Object.keys(packageJson.peerDependencies || {}),
@@ -36,6 +37,7 @@ export default [
36
37
  input: "dist/esm/types/index.d.ts",
37
38
  output: [{ file: "dist/index.d.ts", format: "esm" }],
38
39
  plugins: [dts()],
40
+ inlineDynamicImports: true,
39
41
  external: [
40
42
  ...Object.keys(packageJson.dependencies || {}),
41
43
  ...Object.keys(packageJson.peerDependencies || {}),