@raytio/core 11.1.0 → 11.3.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.
Files changed (93) hide show
  1. package/CHANGELOG.md +17 -2
  2. package/README.md +123 -33
  3. package/dist/accessApplication/api/__tests__/fetchKeysForSubmission.test.d.ts +1 -0
  4. package/dist/accessApplication/api/__tests__/fetchKeysForSubmission.test.js +28 -0
  5. package/dist/accessApplication/api/__tests__/fetchPOsOrAOsForSubmission.test.d.ts +1 -0
  6. package/dist/accessApplication/api/__tests__/fetchPOsOrAOsForSubmission.test.js +23 -0
  7. package/dist/accessApplication/api/__tests__/fetchRelationshipsForSubmission.test.d.ts +1 -0
  8. package/dist/accessApplication/api/__tests__/fetchRelationshipsForSubmission.test.js +27 -0
  9. package/dist/accessApplication/api/__tests__/getMissingDataForInstance.test.d.ts +1 -0
  10. package/dist/accessApplication/api/__tests__/getMissingDataForInstance.test.js +30 -0
  11. package/dist/accessApplication/api/fetchKeysForSubmission.d.ts +12 -0
  12. package/dist/accessApplication/api/fetchKeysForSubmission.js +16 -0
  13. package/dist/accessApplication/api/fetchPOsOrAOsForSubmission.d.ts +6 -0
  14. package/dist/accessApplication/api/fetchPOsOrAOsForSubmission.js +25 -0
  15. package/dist/accessApplication/api/fetchRelationshipsForSubmission.d.ts +6 -0
  16. package/dist/accessApplication/api/fetchRelationshipsForSubmission.js +10 -0
  17. package/dist/accessApplication/api/getMissingDataForInstance.d.ts +10 -0
  18. package/dist/accessApplication/api/getMissingDataForInstance.js +28 -0
  19. package/dist/accessApplication/api/index.d.ts +2 -0
  20. package/dist/accessApplication/api/index.js +18 -0
  21. package/dist/accessApplication/api/legacy/__tests__/convertRelationships.test.d.ts +1 -0
  22. package/dist/accessApplication/api/legacy/__tests__/convertRelationships.test.js +37 -0
  23. package/dist/accessApplication/api/legacy/convertRelationships.d.ts +16 -0
  24. package/dist/accessApplication/api/legacy/convertRelationships.js +21 -0
  25. package/dist/accessApplication/api/legacy/index.d.ts +1 -0
  26. package/dist/accessApplication/api/legacy/index.js +17 -0
  27. package/dist/accessApplication/createAA.js +6 -5
  28. package/dist/accessApplication/index.d.ts +1 -0
  29. package/dist/accessApplication/index.js +1 -0
  30. package/dist/crypto/cognitoAttributes.d.ts +1 -1
  31. package/dist/crypto/decryptSharedData.d.ts +2 -2
  32. package/dist/crypto/decryptSharedData.js +2 -5
  33. package/dist/crypto/getAADecryptor.d.ts +18 -3
  34. package/dist/crypto/getAADecryptor.js +34 -6
  35. package/dist/crypto/helpers.d.ts +2 -2
  36. package/dist/general/types.d.ts +9 -0
  37. package/dist/general/types.js +10 -1
  38. package/dist/rules/calculateScore.d.ts +1 -1
  39. package/dist/rules/convertInstanceToRuleInput.d.ts +3 -3
  40. package/dist/rules/convertInstanceToRuleInput.js +5 -2
  41. package/dist/rules/evaluateScoreCondition.d.ts +1 -1
  42. package/dist/rules/helpers/__tests__/getValuesFromPath.test.js +1 -1
  43. package/dist/rules/helpers/addInfiniteThresholdBoundaries.d.ts +1 -1
  44. package/dist/rules/helpers/checkTypeofValue.d.ts +1 -1
  45. package/dist/rules/helpers/getValuesFromPath.d.ts +1 -1
  46. package/dist/rules/helpers/thresholds.d.ts +1 -1
  47. package/dist/rules/operators/bool.d.ts +1 -1
  48. package/dist/rules/operators/date.d.ts +1 -1
  49. package/dist/rules/operators/hfield.d.ts +1 -1
  50. package/dist/rules/operators/hschema.d.ts +1 -1
  51. package/dist/rules/operators/index.d.ts +1 -1
  52. package/dist/rules/operators/number.d.ts +1 -1
  53. package/dist/rules/operators/string.d.ts +1 -1
  54. package/dist/rules/types/config.d.ts +4 -3
  55. package/dist/rules/types/dataValueTypes.d.ts +2 -3
  56. package/dist/rules/types/internal.d.ts +4 -3
  57. package/dist/rules/validate.d.ts +2 -2
  58. package/dist/schema/expandSchema/__tests__/expandSchema.test.js +8 -7
  59. package/dist/schema/expandSchema/__tests__/i18n.test.js +1 -1
  60. package/dist/schema/expandSchema/__tests__/maybeUseI18n.test.js +2 -2
  61. package/dist/schema/expandSchema/__tests__/processSchema.test.js +6 -6
  62. package/dist/schema/expandSchema/addLoadingTimes.d.ts +1 -1
  63. package/dist/schema/expandSchema/constants.d.ts +1 -1
  64. package/dist/schema/expandSchema/expandSchema.d.ts +1 -1
  65. package/dist/schema/expandSchema/maybeUseI18n.d.ts +1 -1
  66. package/dist/schema/expandSchema/processSchema.d.ts +3 -4
  67. package/dist/schema/expandSchema/processSchema.js +2 -2
  68. package/dist/schema/expandSchema/removePrivateFields.d.ts +8 -6
  69. package/dist/schema/expandSchema/sortSchemaProperties.d.ts +3 -3
  70. package/dist/schema/expandSchema/unwrapSchema.d.ts +2 -6
  71. package/dist/schema/expandSchema/unwrapSchema.js +1 -1
  72. package/dist/schema/labels.d.ts +2 -1
  73. package/dist/testHelpers.d.ts +9 -0
  74. package/dist/testHelpers.js +9 -0
  75. package/dist/verifications/cleanInstance.d.ts +1 -1
  76. package/dist/verifications/getPOVerification.d.ts +1 -1
  77. package/dist/verifications/getPOVerification.js +6 -2
  78. package/dist/verifications/getVerifiedBy.js +6 -1
  79. package/dist/verifications/index.d.ts +0 -1
  80. package/dist/verifications/index.js +0 -1
  81. package/dist/verifications/safeHarbour.d.ts +2 -2
  82. package/dist/verifications/verifyCheck/__tests__/getOwnRealVerifications.test.js +74 -9
  83. package/dist/verifications/verifyCheck/__tests__/getSomeoneElsesRealVerifications.test.js +2 -2
  84. package/dist/verifications/verifyCheck/getOwnRealVerifications.d.ts +1 -1
  85. package/dist/verifications/verifyCheck/getOwnRealVerifications.js +3 -1
  86. package/dist/verifications/verifyCheck/getSomeoneElsesRealVerifications.d.ts +1 -1
  87. package/dist/verifications/verifyCheck/getSomeoneElsesRealVerifications.js +1 -1
  88. package/dist/verifications/verifyCheck/operations/__tests__/checkOwnVerification.test.js +45 -5
  89. package/dist/verifications/verifyCheck/operations/__tests__/checkSomeoneElsesVerifications.test.js +2 -2
  90. package/dist/verifications/verifyCheck/operations/__tests__/sampleBundle.json +1 -0
  91. package/dist/verifications/verifyCheck/operations/checkOwnVerification.d.ts +4 -3
  92. package/dist/verifications/verifyCheck/operations/checkOwnVerification.js +17 -8
  93. package/package.json +6 -42
@@ -1,10 +1,10 @@
1
- import { Schema } from "@raytio/types";
1
+ import type { Schema } from "@raytio/types";
2
2
  export declare const removePrivateFields: (schema: Schema) => {
3
3
  properties: Record<string, Omit<import("@raytio/types").SchemaField, "$id" | "allOf" | "$schema" | "definitions">>;
4
- type?: import("@raytio/types").DataTypes | undefined;
5
- name: string;
6
4
  title: string;
7
5
  description: string;
6
+ description_decorator?: "md" | undefined;
7
+ schema_type?: import("@raytio/types").SchemaType | undefined;
8
8
  title_plural?: string | undefined;
9
9
  schema_group?: string | undefined;
10
10
  tags?: import("@raytio/types").SchemaTag[] | undefined;
@@ -59,8 +59,8 @@ export declare const removePrivateFields: (schema: Schema) => {
59
59
  direction: "from";
60
60
  type: string;
61
61
  required_relationship?: boolean | undefined;
62
- oneOf?: string[] | undefined;
63
- anyOf?: string[] | undefined;
62
+ oneOf?: (import("@raytio/types").SchemaName | "instance")[] | undefined;
63
+ anyOf?: import("@raytio/types").SchemaName[] | undefined;
64
64
  multiple?: boolean | undefined;
65
65
  properties?: {
66
66
  [fieldName: string]: import("@raytio/types").SchemaField;
@@ -83,7 +83,7 @@ export declare const removePrivateFields: (schema: Schema) => {
83
83
  } | undefined;
84
84
  onboard_properties?: {
85
85
  profile_objects?: {
86
- schema_name: string;
86
+ schema_name: import("@raytio/types").SchemaName;
87
87
  properties: Record<string, unknown>;
88
88
  }[] | undefined;
89
89
  relationships?: {
@@ -104,6 +104,8 @@ export declare const removePrivateFields: (schema: Schema) => {
104
104
  }[] | undefined;
105
105
  return_to?: string | undefined;
106
106
  } | undefined;
107
+ name: import("@raytio/types").SchemaName;
108
+ type?: import("@raytio/types").DataTypes | undefined;
107
109
  group_title?: string | undefined;
108
110
  verified_fields?: (string | import("@raytio/types").ConditionallyRequired)[] | undefined;
109
111
  required?: (string | import("@raytio/types").ConditionallyRequired)[] | undefined;
@@ -1,8 +1,8 @@
1
- import { NId, SchemaField, Urn } from "@raytio/types";
1
+ import type { NId, SchemaField, Urn } from "@raytio/types";
2
2
  /** two overloads - if you provide undefined, you might get undefined back */
3
3
  export declare const getNidFromUrn: {
4
- (urn: Urn): NId;
5
- (urn: Urn | undefined): NId | undefined;
4
+ <IDType = NId>(urn: Urn): IDType;
5
+ <IDType_1 = NId>(urn: Urn | undefined): IDType_1 | undefined;
6
6
  };
7
7
  type Key = string;
8
8
  type Tag = string;
@@ -1,6 +1,2 @@
1
- import { WrappedSchema } from "@raytio/types";
2
- export declare function unwrapSchema(wrapped: WrappedSchema): WrappedSchema["schema"] & {
3
- version: string;
4
- start_date?: string;
5
- end_date?: string;
6
- };
1
+ import type { Schema, WrappedSchema } from "@raytio/types";
2
+ export declare function unwrapSchema(wrapped: WrappedSchema): WrappedSchema["schema"] & Pick<WrappedSchema, "start_date" | "end_date" | "schema_type"> & Pick<Schema, "name" | "version">;
@@ -2,6 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.unwrapSchema = void 0;
4
4
  function unwrapSchema(wrapped) {
5
- return Object.assign(Object.assign({}, wrapped.schema), { name: wrapped.name, start_date: wrapped.start_date, end_date: wrapped.end_date, version: wrapped.version });
5
+ return Object.assign(Object.assign({}, wrapped.schema), { name: wrapped.schema_name, start_date: wrapped.start_date, end_date: wrapped.end_date, version: wrapped.schema_version, schema_type: wrapped.schema_type });
6
6
  }
7
7
  exports.unwrapSchema = unwrapSchema;
@@ -1,2 +1,3 @@
1
+ import type { SchemaName } from "@raytio/types";
1
2
  /** Finds the label (on a profile object) which is the schema name */
2
- export declare const findSchemaLabel: (labels: string[] | undefined) => string | undefined;
3
+ export declare const findSchemaLabel: (labels: string[] | undefined) => SchemaName | undefined;
@@ -0,0 +1,9 @@
1
+ import type { Mock } from "vitest";
2
+ /** like {@link Partial} but applies to all deep properties */
3
+ export type DeepPartial<T> = T | (T extends object ? {
4
+ [K in keyof T]?: DeepPartial<T[K]>;
5
+ } : T extends (infer U)[] ? DeepPartial<U>[] : T);
6
+ /** tells typescript that this function is mocked */
7
+ export declare const m: (func: unknown) => Mock<any, any>;
8
+ /** helper to let us define type-safe partial mocks */
9
+ export declare const deepPartial: <T>(partial: DeepPartial<T>) => T;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepPartial = exports.m = void 0;
4
+ /** tells typescript that this function is mocked */
5
+ const m = (func) => func;
6
+ exports.m = m;
7
+ /** helper to let us define type-safe partial mocks */
8
+ const deepPartial = (partial) => partial;
9
+ exports.deepPartial = deepPartial;
@@ -1,4 +1,4 @@
1
- import { Instance } from "@raytio/types";
1
+ import type { Instance } from "@raytio/types";
2
2
  /**
3
3
  * The API response from share/v2/access_application/instance/:iId
4
4
  * returns a complicated hashed_n_id format, so you need to clean up
@@ -1,4 +1,4 @@
1
- import { FieldVerification, ProfileObject, POVerification, RealVer, Schema, VerificationProvider, ProfileObjectForUpload, NId } from "@raytio/types";
1
+ import { FieldVerification, type NId, POVerification, type ProfileObject, type ProfileObjectForUpload, type RealVer, type Schema, type VerificationProvider } from "@raytio/types";
2
2
  export type VerDetails = {
3
3
  sourceNId?: NId;
4
4
  verifiers: VerificationProvider[];
@@ -55,10 +55,13 @@ function getPOVerification({ PO, schema, realVers, }) {
55
55
  if (pertainingVers.length && pertainingVers.every(x => x.expired)) {
56
56
  return types_1.FieldVerification.Expired;
57
57
  }
58
- if (pertainingVers.some(x => !x.verified)) {
58
+ // the if statement above checks if every ver is expired. It is possible
59
+ // that only some are expired, so filter out those ones.
60
+ const nonExpiredPertainingVers = pertainingVers.filter(x => !x.expired);
61
+ if (nonExpiredPertainingVers.some(x => !x.verified)) {
59
62
  return types_1.FieldVerification.VerifiedFalse;
60
63
  }
61
- return pertainingVers.length
64
+ return nonExpiredPertainingVers.length
62
65
  ? types_1.FieldVerification.Verified
63
66
  : types_1.FieldVerification.NotVerified;
64
67
  }, shouldBeVerifiedProps);
@@ -89,6 +92,7 @@ function getPOVerification({ PO, schema, realVers, }) {
89
92
  nId: PO.n_id,
90
93
  realVers,
91
94
  shouldBeVerifiedProps,
95
+ verificationStatus: status,
92
96
  });
93
97
  // find the earliest expiry date if there is one
94
98
  const maybeExpiryDate = ((_c = (0, ramda_1.sortBy)(ver => +ver.expired, realVers.filter(ver => ver.belongsToNId === PO.n_id && ver.expired))[0]) === null || _c === void 0 ? void 0 : _c.expired) || undefined;
@@ -1,13 +1,18 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getVerifiedBy = void 0;
4
+ const types_1 = require("@raytio/types");
4
5
  const ramda_1 = require("ramda");
5
6
  const maybeRereference_1 = require("./maybeRereference");
6
7
  // we should probably document this
7
8
  /** @internal */
8
- const getVerifiedBy = ({ nId, realVers, shouldBeVerifiedProps, }) => {
9
+ const getVerifiedBy = ({ nId, realVers, shouldBeVerifiedProps, verificationStatus, }) => {
9
10
  const mayBeVerifiedFields = Object.keys(shouldBeVerifiedProps);
10
11
  const pertainingVers = realVers
12
+ // for valid verifications, we filter out the information that came from
13
+ // now expired sources. We only ever consider expired source if the verification
14
+ // itself is expired.
15
+ .filter(realVer => realVer.expired ? verificationStatus === types_1.POVerification.Expired : true)
11
16
  .filter(x => mayBeVerifiedFields.includes(x.fieldName) &&
12
17
  // using ramda's `equals` because this needs to work for objects/arrays
13
18
  (0, ramda_1.equals)((0, maybeRereference_1.maybeRereference)(shouldBeVerifiedProps[x.fieldName]), (0, maybeRereference_1.maybeRereference)(x.value)) &&
@@ -1,4 +1,3 @@
1
- export * from "./cleanInstance";
2
1
  export * from "./getPOVerification";
3
2
  export * from "./verifyCheck";
4
3
  export * from "./getVerifiedBy";
@@ -14,7 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./cleanInstance"), exports);
18
17
  __exportStar(require("./getPOVerification"), exports);
19
18
  __exportStar(require("./verifyCheck"), exports);
20
19
  __exportStar(require("./getVerifiedBy"), exports);
@@ -1,4 +1,4 @@
1
- import { ProfileObject, RealVer, SafeHarbourCode, Schema } from "@raytio/types";
1
+ import { type ProfileObject, type RealVer, type SafeHarbourCode, type Schema, type SchemaName } from "@raytio/types";
2
2
  /** an object listing the `xId`s for each SafeHarbourCode */
3
3
  export type SafeHarbourObj = Partial<Record<SafeHarbourCode, string[]>>;
4
4
  /** the response from {@link calcSafeHarbourScore} */
@@ -16,5 +16,5 @@ export declare const calcSafeHarbourScore: (data: {
16
16
  person: ProfileObject;
17
17
  profileObjects: ProfileObject[];
18
18
  realVers: RealVer[];
19
- getSchema(schemaName: string): Promise<Schema>;
19
+ getSchema(schemaName: SchemaName): Promise<Schema>;
20
20
  }) => Promise<SafeHarbourResult>;
@@ -2,7 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const __1 = require("..");
4
4
  const operations_1 = require("../operations");
5
- jest.mock("../operations");
5
+ const testHelpers_1 = require("../../../testHelpers");
6
+ vi.mock("../operations");
6
7
  /**
7
8
  * in this test case:
8
9
  * - there are valid verifications for fName=Max and fName=Erika, but we don't which
@@ -16,22 +17,25 @@ jest.mock("../operations");
16
17
  */
17
18
  describe("getOwnRealVerifications", () => {
18
19
  beforeAll(() => {
19
- operations_1.checkOwnVerification.mockImplementation(async ({ signature }) => {
20
+ vi.fn(() => 1).mockImplementation(() => 123);
21
+ (0, testHelpers_1.m)(operations_1.checkOwnVerification).mockImplementation(async ({ signature, keyId }) => {
20
22
  if (signature === "signatureForLastNameMustermannFromN2")
21
23
  return false;
24
+ if (keyId === "thisOneIsInvalid")
25
+ return false;
22
26
  return true;
23
27
  });
24
28
  });
25
29
  it("calls the verifyCheck function for each PO, keeping only the valid ones", async () => {
26
- const profileObjects = [
30
+ const profileObjects = (0, testHelpers_1.deepPartial)([
27
31
  { n_id: "n1", properties: { fName: "Max", lName: "Mustermann" } },
28
32
  { n_id: "n2", properties: { fName: "Erika", lName: "Mustermann" } },
29
- ];
30
- const verifications = [
33
+ ]);
34
+ const verifications = (0, testHelpers_1.deepPartial)([
31
35
  {
32
36
  n_id: "nv1",
33
37
  properties: {
34
- valid_until: "2020-08-28T23:12:35.678Z",
38
+ valid_until: "2020-08-28T23:12:35.678Z", // this one has expired
35
39
  verifications: [
36
40
  {
37
41
  signature: "signatureForFirstNameMax",
@@ -65,6 +69,7 @@ describe("getOwnRealVerifications", () => {
65
69
  passed: false,
66
70
  source_n_id: "n2",
67
71
  },
72
+ // legacy: key_id is not specified
68
73
  },
69
74
  ],
70
75
  },
@@ -103,14 +108,56 @@ describe("getOwnRealVerifications", () => {
103
108
  ],
104
109
  },
105
110
  },
106
- ];
111
+ {
112
+ n_id: "nv6",
113
+ properties: {
114
+ verifications: [
115
+ {
116
+ signature: "signatureForFirstNameErika",
117
+ data: {
118
+ field: "fName",
119
+ verifier_source_id: "Ministry of pike river mine re-entry",
120
+ verifier_service_id: "Minister for pike river re-entry",
121
+ verifier_id: "v1",
122
+ verification_date: "2020-08-28T23:11:20.592912",
123
+ request_div: "x2",
124
+ passed: false,
125
+ source_n_id: "n2",
126
+ },
127
+ key_id: "thisOneIsInvalid", // signature & data is good, but this key will fail
128
+ },
129
+ ],
130
+ },
131
+ },
132
+ {
133
+ n_id: "nv7",
134
+ properties: {
135
+ verifications: [
136
+ {
137
+ signature: "signatureForFirstNameErika",
138
+ data: {
139
+ field: "fName",
140
+ verifier_source_id: "Ministry of pike river mine re-entry",
141
+ verifier_service_id: "Minister for pike river re-entry",
142
+ verifier_id: "v1",
143
+ verification_date: "2020-08-28T23:11:20.592912",
144
+ request_div: "x2",
145
+ passed: false,
146
+ source_n_id: "n2",
147
+ },
148
+ key_id: "raytio", // everything is valid, this is the right key_id
149
+ },
150
+ ],
151
+ },
152
+ },
153
+ ]);
107
154
  const realVers = await (0, __1.getOwnRealVerifications)({
108
155
  profileObjects,
109
156
  verifications,
110
157
  userId: "geesepolice2002",
111
158
  });
112
- expect(operations_1.checkOwnVerification).toHaveBeenCalledTimes(3);
113
- // 3 times, not 5. Because this new method doesn't need to build a big matrix of possible combinations
159
+ expect(operations_1.checkOwnVerification).toHaveBeenCalledTimes(5);
160
+ // 5 times. Because this new method doesn't need to build a big matrix of possible combinations
114
161
  expect(realVers).toStrictEqual([
115
162
  {
116
163
  fieldName: "fName",
@@ -147,6 +194,24 @@ describe("getOwnRealVerifications", () => {
147
194
  xId: "x2",
148
195
  },
149
196
  // note how lastName is not included since it's invalid
197
+ // nv6 is not included because the key is invalid
198
+ {
199
+ fieldName: "fName",
200
+ value: "Erika",
201
+ belongsToNId: "n2",
202
+ nID: "nv7",
203
+ expired: false,
204
+ metadata: undefined,
205
+ provider: {
206
+ dataSourceNId: "Ministry of pike river mine re-entry",
207
+ date: new Date("2020-08-28T23:11:20.592Z"),
208
+ serviceProviderNId: "Minister for pike river re-entry",
209
+ verifierNId: "v1",
210
+ },
211
+ signature: "signatureForFirstNameErika",
212
+ verified: false,
213
+ xId: "x2",
214
+ },
150
215
  ]);
151
216
  });
152
217
  });
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const getSomeoneElsesRealVerifications_1 = require("../getSomeoneElsesRealVerifications");
4
4
  const operations_1 = require("../operations");
5
- jest.mock("../operations");
5
+ vi.mock("../operations");
6
6
  const checkVerificationsResp = [
7
7
  {
8
8
  verified: false,
@@ -133,7 +133,7 @@ const verifications = [
133
133
  ];
134
134
  describe("getSomeoneElsesRealVerifications", () => {
135
135
  beforeEach(() => {
136
- jest.resetAllMocks();
136
+ vi.resetAllMocks();
137
137
  operations_1.checkSomeoneElsesVerifications.mockResolvedValue(checkVerificationsResp);
138
138
  });
139
139
  it("returns an empty array if provided nothing", async () => {
@@ -1,4 +1,4 @@
1
- import { ProfileObject, Verification, RealVer, UId } from "@raytio/types";
1
+ import type { ProfileObject, RealVer, UId, Verification } from "@raytio/types";
2
2
  /**
3
3
  * Given a list of verifications and decrypted profile objects, this function
4
4
  * locally verifies the credibility of the signatures in the verifications.
@@ -17,7 +17,8 @@ const getOwnRealVerifications = async ({ verifications, profileObjects, userId,
17
17
  // because attempting hundreds of webcrypto operations simultaneously will
18
18
  // probably upset some heritage web browser.
19
19
  for (const ver of verifications) {
20
- for (const { data, signature } of ver.properties.verifications) {
20
+ for (const verPO of ver.properties.verifications) {
21
+ const { data, signature } = verPO;
21
22
  const sourcePO = profileObjects.find(PO => PO.n_id === data.source_n_id);
22
23
  if (!sourcePO)
23
24
  continue;
@@ -34,6 +35,7 @@ const getOwnRealVerifications = async ({ verifications, profileObjects, userId,
34
35
  userId,
35
36
  value: (0, maybeRereference_1.maybeRereference)(value),
36
37
  signature,
38
+ keyId: verPO.key_id,
37
39
  });
38
40
  if (!isGenuine)
39
41
  continue;
@@ -1,4 +1,4 @@
1
- import { ProfileObject, Verification, RealVer, AId } from "@raytio/types";
1
+ import type { AId, ProfileObject, RealVer, Verification } from "@raytio/types";
2
2
  type Props = {
3
3
  aId: AId;
4
4
  apiUrl: string;
@@ -64,7 +64,7 @@ const getSomeoneElsesRealVerifications = async ({ aId, apiUrl, verifications, pr
64
64
  verified: data.passed,
65
65
  nID,
66
66
  belongsToNId: data.source_hashed_n_id
67
- ? `HASHED::${data.source_hashed_n_id}::${aId}`
67
+ ? (0, general_1.createHashedNId)(data.source_hashed_n_id, aId)
68
68
  : data.source_n_id,
69
69
  }));
70
70
  return realVers;
@@ -7,8 +7,9 @@ const __1 = require("..");
7
7
  const util_1 = require("../../../../util");
8
8
  const checkOwnVerification_1 = require("../checkOwnVerification");
9
9
  const sampleBundle_json_1 = __importDefault(require("./sampleBundle.json"));
10
- Reflect.set(global, "fetch", jest.fn().mockResolvedValue({
11
- text: async () => `-----BEGIN PUBLIC KEY-----
10
+ global.fetch = vi.fn().mockImplementation(async (url) => ({
11
+ text: async () => url.endsWith("raytio.pem")
12
+ ? `-----BEGIN PUBLIC KEY-----
12
13
  MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAn9QtCqYa3H3ipFFU0xP3
13
14
  n6r7KHS3GMbh0h/xzel57HhCIaXDYjUeUtgUNtzm+uElb/qzGn50xQRzVqO32vKB
14
15
  ZAW2kYyZ2+R5ruk9CSxr7K4Vk1FtDMcUCzqxm0eycFD2xbLsN3feRc3BMjfdaQ7P
@@ -21,10 +22,29 @@ Gut0BoM+DIwDu0uZaUprz7fSgNmYHHEiIFbOMVHiOn8oZAZbJXXbUbFIUYXA8u9+
21
22
  J1Z+QEpgw+rhGzOf/TSeHfMC9nNbWgYglluAJusWf2XwG/t/VlhtzviHCVGEL7HQ
22
23
  jQE5DrM7vaTg6Gu9bjKuoeLIRzbOYK6qAWFoa0CLcN84PLjhDSRw2duatP08hcWg
23
24
  jTgOkLWnBFE7NyRU93uPp68CAwEAAQ==
25
+ -----END PUBLIC KEY-----`
26
+ : `-----BEGIN PUBLIC KEY-----
27
+ MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAgee+uBOgOsbwjMvGN1/H
28
+ qpGXGJLol0Pc2KhI1fh1NBq+UGhk8PqgDd5wHZikbmrtVkvp/maIh+mbIdehY/RC
29
+ ftMylvebCf4Qf+5SWzQsmB1o6nBUbwJzYE2XyvxRiNLhdIeE+GgfdpA5S3l0cDJ5
30
+ B/1TagITmQUjThwTxDYZ6jlGJJ4NSjqlqeQrHhGWRLVQPWU8bYysX3jt3/uiv4tS
31
+ n3TheLGY1TMlbFrVF2Spv1WxuqMZ4bX1mIotK3yEB3TaZSZaOwlUcEZ4xY+J4Vl+
32
+ ZlrOgYbmzFd7UFh9UZbYZUkNSEfddEnFNFlFG3YQVt8UAumPBVJELdjiaRjTj/K4
33
+ 62GAFyOcbcw9wcl69fPBnieBo2m2Dqf6U3wcrnvTnkMwjCewWXCH6FdbC4OllBZV
34
+ Nrfn6zf9yX0J8ZEDEcw9ZsNLVkyl2U+Ya/h5CQt43ip/1eNM5LpTbfqBTtAH7iUO
35
+ 4L9rxuSJFA2Q9kZfof6kYO9EGgMFB+GM47/Q068+IiTpifvPno4ilnowyS4hbLiy
36
+ Os2yudW79flaz0a7rq5dLdSg9Mm5k7ETBm7WguDcocaiETmuYTJT2PozAGOC3+EP
37
+ w5N7mQff4ecx/880FWYKQmU9Asav1V49DWSnG0ZXQ7U24dG8ANeAgKddDviJGlsh
38
+ SsjKrz8LJqeoNQu30iSGZhUCAwEAAQ==
24
39
  -----END PUBLIC KEY-----`,
25
40
  }));
26
41
  describe("checkOwnVerification", () => {
27
- it("works for a real PO", async () => {
42
+ it.each `
43
+ keyId | result
44
+ ${undefined} | ${true}
45
+ ${"whatever/raytio"} | ${true}
46
+ ${"whatever/somethingElse"} | ${false}
47
+ `("returns $result for a PO with keyId=$keyId", async ({ keyId, result }) => {
28
48
  //
29
49
  // This is an important integration test from ca. 2021-12-02.
30
50
  // If it is failing, it means our code no longer matches the
@@ -54,7 +74,13 @@ describe("checkOwnVerification", () => {
54
74
  };
55
75
  const value = "NZ Limited Company";
56
76
  const userId = "fd9c4903-65c2-4b75-b454-4fda6b682f3e"; // for 27july21 🦈
57
- expect(await (0, checkOwnVerification_1.checkOwnVerification)({ value, signature, userId, verObject })).toBe(true);
77
+ expect(await (0, checkOwnVerification_1.checkOwnVerification)({
78
+ value,
79
+ signature,
80
+ userId,
81
+ verObject,
82
+ keyId,
83
+ })).toBe(result);
58
84
  });
59
85
  it("errors if you forget to supply the uId", async () => {
60
86
  await expect(() => (0, checkOwnVerification_1.checkOwnVerification)({
@@ -62,8 +88,22 @@ describe("checkOwnVerification", () => {
62
88
  signature: "",
63
89
  userId: "",
64
90
  verObject: {},
91
+ keyId: undefined,
65
92
  })).rejects.toThrow(new Error("No userId supplied"));
66
93
  });
94
+ it.each `
95
+ keyId
96
+ ${"../../malicious.pem"}
97
+ ${"https://example.com/malicious.pem"}
98
+ `("errors if you supply an invalid keyId", async ({ keyId }) => {
99
+ await expect(() => (0, checkOwnVerification_1.checkOwnVerification)({
100
+ value: "whatever",
101
+ signature: "whatever",
102
+ userId: "whatever",
103
+ verObject: {},
104
+ keyId,
105
+ })).rejects.toThrow(new Error("Invalid key ID"));
106
+ });
67
107
  });
68
108
  describe("checkSignature", () => {
69
109
  it("works", async () => {
@@ -86,6 +126,6 @@ describe("checkSignature", () => {
86
126
  });
87
127
  describe("checkJsonSignature", () => {
88
128
  it("can verify a bundled verification", async () => {
89
- expect(await (0, __1.checkJsonSignature)(sampleBundle_json_1.default.data, sampleBundle_json_1.default.signature)).toBe(true);
129
+ expect(await (0, __1.checkJsonSignature)(sampleBundle_json_1.default.data, sampleBundle_json_1.default.signature, sampleBundle_json_1.default.key_id)).toBe(true);
90
130
  });
91
131
  });
@@ -13,7 +13,7 @@ const toVerify = [
13
13
  ];
14
14
  describe("checkSomeoneElsesVerifications", () => {
15
15
  it("calls the API and filters out garbage", async () => {
16
- global.fetch = jest
16
+ global.fetch = vi
17
17
  .fn()
18
18
  .mockImplementation()
19
19
  // first fetch request
@@ -34,7 +34,7 @@ describe("checkSomeoneElsesVerifications", () => {
34
34
  expect(result).toStrictEqual([{ verified: true }, { verified: false }]);
35
35
  });
36
36
  it("throws an error if the API rejects", async () => {
37
- global.fetch = jest
37
+ global.fetch = vi
38
38
  .fn()
39
39
  .mockImplementation()
40
40
  // first fetch request
@@ -39,5 +39,6 @@
39
39
  },
40
40
  "valid_until": "2022-03-13T02:26:20.468171"
41
41
  },
42
+ "key_id": "any string/raytio",
42
43
  "signature": "AiWWrL+S1paYOqJiOtU3qwLTCkkZjwDq3FuHl7oy14IATYOhCeHLf+ca44X1Wc6pYpTQckjKnJZL\nkfgiwNE97aymWIOc+ZZGEb5YhXRNO+inTV4k5zppaDN3n3YAGzn7zMxleh3+opzJqncNaJtpZ0Wv\na9Pu/m4WjyT5ee3Myz6VOOMuVkcaTL4FD8XT7NdCh0ybRevAZ5R9xl0YuWMhvNpf3P6ieTikHXYN\nkKbPTnAhNdBmqV4njSIR66M82Ek0d9VcsX4zhmlhpdCmGRlXLgHEyMCF4iHlCIxSeKtGaOm2QK2R\nOV/lN3VScDNWyD8lPBipcj++5ZGII6BnFFG8LlT3gY/Y/wt8KeH/xgdu0a7Lt6J/BOiGLFfscUmb\nH5K5t48gnQ5BQS+Cf/yhayMV49LlGiK9m1iPlbmuJH1L2/ZM+iLsIrSTGCU0Rpbkw7qvm0dkUNYf\nhvlj/RnUxcy0Lr/84CzLvBhFMmBX+RHlcPrCWpIiibsdaD81kRyvLY2TASLFTeHajfr+UvtP3LVs\n8NGwRQHd6c2/ptxv3ERRUnDtNASatsLe67ZHg9SeF3BDhMHZwU1neYyrBI1TMECasFli5rP5gviq\nC8ZwFQ9lnDDTidWBF8GjRl6ope4wIuNBBkOsIIeyqIJE5BRUH4LhVUnN1be696uCKnWOyOo7fkc=\n"
43
44
  }
@@ -1,15 +1,16 @@
1
- import { UId, VerificationPayload } from "@raytio/types";
1
+ import type { UId, VerificationPayload } from "@raytio/types";
2
2
  type SingleVerToCheck = {
3
3
  verObject: VerificationPayload<false>;
4
4
  signature: string;
5
5
  userId: UId;
6
6
  value: unknown;
7
+ keyId: string | undefined;
7
8
  };
8
9
  /**
9
10
  * checks that a json object was signed by the provided signature. Unless you're
10
11
  * dealing with bundled verifications, you should use `getOwnRealVerifications`
11
12
  * or `getSomeoneElsesRealVerifications` instead.
12
13
  */
13
- export declare const checkJsonSignature: (data: unknown, signature: string) => Promise<boolean>;
14
- export declare const checkOwnVerification: ({ verObject, signature, userId, value, }: SingleVerToCheck) => Promise<boolean>;
14
+ export declare const checkJsonSignature: (data: unknown, signature: string, keyId: string | undefined) => Promise<boolean>;
15
+ export declare const checkOwnVerification: ({ verObject, signature, userId, value, keyId, }: SingleVerToCheck) => Promise<boolean>;
15
16
  export {};
@@ -2,14 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.checkOwnVerification = exports.checkJsonSignature = exports.checkSignature = void 0;
4
4
  const util_1 = require("../../../util");
5
- let cache;
5
+ const cache = {};
6
6
  const base64ToArrayBuffer = (str) => Uint8Array.from(atob(str), c => c.charCodeAt(0));
7
- async function getJwk() {
7
+ async function getJwk(keyUrl) {
8
8
  // eslint-disable-next-line fp/no-mutation
9
- cache || (cache = fetch("https://api-docs.rayt.io/lookups/raytio.pem")
9
+ cache[keyUrl] || (cache[keyUrl] = fetch(keyUrl)
10
10
  .then(r => r.text())
11
11
  .then(pem => crypto.subtle.importKey("spki", base64ToArrayBuffer(pem.split("-----")[2].trim()), { name: "RSA-PSS", hash: "SHA-512" }, false, ["verify"])));
12
- return cache;
12
+ return cache[keyUrl];
13
13
  }
14
14
  /** @internal exported only for tests */
15
15
  async function checkSignature(publicCryptoKey, signature, data) {
@@ -24,16 +24,25 @@ exports.checkSignature = checkSignature;
24
24
  * dealing with bundled verifications, you should use `getOwnRealVerifications`
25
25
  * or `getSomeoneElsesRealVerifications` instead.
26
26
  */
27
- const checkJsonSignature = async (data, signature) => {
28
- const jwk = await getJwk();
27
+ const checkJsonSignature = async (data, signature, keyId) => {
28
+ const keyFileName = keyId ? keyId.split("/")[1] : "raytio";
29
+ // don't allow any special characters, e.g. to prevent
30
+ // someone using a keyID of "../../someOtherFile"
31
+ if (!keyFileName || /[^\w-]/.test(keyFileName)) {
32
+ throw new Error("Invalid key ID");
33
+ }
34
+ // NOTE: We have to hard code the URL, we can't use an environment
35
+ // variable here, since this package is used outside of the monorepo.
36
+ const keyUrl = `https://api-docs.rayt.io/lookups/${keyFileName}.pem`;
37
+ const jwk = await getJwk(keyUrl);
29
38
  const stringified = (0, util_1.canonicalJsonify)(data);
30
39
  const result = await checkSignature(jwk, signature, stringified);
31
40
  return result;
32
41
  };
33
42
  exports.checkJsonSignature = checkJsonSignature;
34
- const checkOwnVerification = async ({ verObject, signature, userId, value, }) => {
43
+ const checkOwnVerification = async ({ verObject, signature, userId, value, keyId, }) => {
35
44
  if (!userId)
36
45
  throw new Error("No userId supplied");
37
- return (0, exports.checkJsonSignature)(Object.assign(Object.assign({}, verObject), { sub: userId, value }), signature);
46
+ return (0, exports.checkJsonSignature)(Object.assign(Object.assign({}, verObject), { sub: userId, value }), signature, keyId);
38
47
  };
39
48
  exports.checkOwnVerification = checkOwnVerification;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raytio/core",
3
- "version": "11.1.0",
3
+ "version": "11.3.0",
4
4
  "license": "MIT",
5
5
  "main": "index",
6
6
  "types": "index",
@@ -12,52 +12,16 @@
12
12
  ],
13
13
  "scripts": {
14
14
  "docs": "sh ../../scripts/generate-docs.sh",
15
- "build": "tsc && rimraf dist/jest.setup.* dist/**/__tests__",
16
- "test": "jest && yarn docs"
15
+ "build": "tsc && rimraf dist/**/__tests__",
16
+ "test": "vitest && yarn docs"
17
17
  },
18
18
  "dependencies": {
19
19
  "@raytio/maxcryptor": "3.1.0",
20
- "@raytio/types": "7.1.0",
21
- "ramda": "0.29.0"
20
+ "@raytio/types": "7.3.0",
21
+ "ramda": "0.29.1"
22
22
  },
23
23
  "devDependencies": {
24
- "@types/ramda": "0.29.0",
25
- "jest": "29.5.0",
26
- "ts-jest": "29.1.0"
27
- },
28
- "jest": {
29
- "transform": {
30
- "^.+\\.(t|j)sx?$": "ts-jest"
31
- },
32
- "testEnvironment": "node",
33
- "collectCoverage": false,
34
- "coverageThreshold": {
35
- "global": {
36
- "statements": 100
37
- }
38
- },
39
- "collectCoverageFrom": [
40
- "**/*.js",
41
- "**/*.ts",
42
- "**/*.tsx"
43
- ],
44
- "coveragePathIgnorePatterns": [
45
- "/dist/",
46
- "/coverage/"
47
- ],
48
- "modulePathIgnorePatterns": [
49
- "/dist/"
50
- ],
51
- "reporters": [
52
- "default",
53
- "jest-junit"
54
- ],
55
- "setupFilesAfterEnv": [
56
- "./src/jest.setup.ts"
57
- ]
58
- },
59
- "jest-junit": {
60
- "outputDirectory": "../../tmp"
24
+ "@types/ramda": "0.29.7"
61
25
  },
62
26
  "engineStrict": true,
63
27
  "engines": {