@roster-lock/shared 0.1.0 → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.humanInfoSchema = exports.friendlyStringSchemaValidator = exports.urlSchemaValidator = void 0;
3
+ exports.humanInfoSchema = exports.friendlyStringSchemaValidator = exports.imageDataURISchemaValidator = exports.urlSchemaValidator = void 0;
4
4
  const json_schema_1 = require("../../../../../util-types/json-schema");
5
5
  const validate_1 = require("../validate");
6
6
  exports.urlSchemaValidator = (0, json_schema_1.defineKeyword)({
@@ -8,6 +8,11 @@ exports.urlSchemaValidator = (0, json_schema_1.defineKeyword)({
8
8
  type: "string",
9
9
  validate: validate_1.validateURL
10
10
  });
11
+ exports.imageDataURISchemaValidator = (0, json_schema_1.defineKeyword)({
12
+ keyword: "imageDataURI",
13
+ type: "string",
14
+ validate: validate_1.validateImageDataURI
15
+ });
11
16
  const human_1 = require("../validate/human");
12
17
  exports.friendlyStringSchemaValidator = (0, json_schema_1.defineKeyword)({
13
18
  keyword: "friendlyString",
@@ -22,7 +27,7 @@ exports.humanInfoSchema = {
22
27
  name: { type: "string", [exports.friendlyStringSchemaValidator.keyword]: true },
23
28
  author: { type: "string", [exports.friendlyStringSchemaValidator.keyword]: true },
24
29
  url: { type: "string", [exports.urlSchemaValidator.keyword]: true },
25
- image: { type: "string", [exports.urlSchemaValidator.keyword]: true, nullable: true },
30
+ image: { type: "string", [exports.imageDataURISchemaValidator.keyword]: true, nullable: true },
26
31
  },
27
32
  };
28
33
  //# sourceMappingURL=human.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"human.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.ts"],"names":[],"mappings":";;;AAGA,uEAAsE;AAGtE,0CAA0C;AAC7B,QAAA,kBAAkB,GAAG,IAAA,2BAAa,EAAC;IAC9C,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,sBAAW;CACtB,CAAC,CAAC;AAEH,6CAA2D;AAC9C,QAAA,6BAA6B,GAAG,IAAA,2BAAa,EAAC;IACzD,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,8BAAsB;CACjC,CAAC,CAAC;AAGU,QAAA,eAAe,GAAiD;IAC3E,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;IAC3B,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;IACnC,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,6BAA6B,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;QACvE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,6BAA6B,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;QACzE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;QAC3D,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;KAC9E;CACF,CAAA"}
1
+ {"version":3,"file":"human.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/human.ts"],"names":[],"mappings":";;;AAGA,uEAAsE;AAGtE,0CAAgE;AACnD,QAAA,kBAAkB,GAAG,IAAA,2BAAa,EAAC;IAC9C,OAAO,EAAE,KAAK;IACd,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,sBAAW;CACtB,CAAC,CAAC;AAEU,QAAA,2BAA2B,GAAG,IAAA,2BAAa,EAAC;IACvD,OAAO,EAAE,cAAc;IACvB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,+BAAoB;CAC/B,CAAC,CAAC;AAEH,6CAA2D;AAC9C,QAAA,6BAA6B,GAAG,IAAA,2BAAa,EAAC;IACzD,OAAO,EAAE,gBAAgB;IACzB,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,8BAAsB;CACjC,CAAC,CAAC;AAGU,QAAA,eAAe,GAAiD;IAC3E,IAAI,EAAE,QAAQ;IACd,oBAAoB,EAAE,KAAK;IAC3B,QAAQ,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC;IACnC,UAAU,EAAE;QACV,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,6BAA6B,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;QACvE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,6BAA6B,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;QACzE,GAAG,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE;QAC3D,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,QAAA,2BAA2B,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE;KACvF;CACF,CAAA"}
@@ -52,6 +52,7 @@ exports.rostersSchema = {
52
52
  exports.rosterKeywords = [
53
53
  downloadableSources_1.downloadableSourceListSchemaValidator,
54
54
  human_1.urlSchemaValidator,
55
+ human_1.imageDataURISchemaValidator,
55
56
  human_1.friendlyStringSchemaValidator,
56
57
  id_1.idSchemaValidator,
57
58
  id_1.idUniquenessSchemaValidator,
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.ts"],"names":[],"mappings":";;;AACA,uEAAsE;AAItE,6BAAgF;AAChF,uCAAiE;AACjE,mCAA6F;AAC7F,+DAG+B;AAC/B,mDAKyB;AACzB,qDAK0B;AAG1B,MAAM,gCAAgC,GAAG,IAAA,2BAAa,EAAC;IACrD,OAAO,EAAE,yBAAyB;IAClC,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,UAAU,KAAsB,EAAE,EAAE,MAAM,EAAsB,EAAE,IAAI;QAE9E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,IAAG,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAA,gCAAqB,EAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;CACF,CAAC,CAAC;AAEU,QAAA,eAAe,GAAoC;IAC9D,IAAI,EAAE,QAAQ;IACd,CAAC,gCAAgC,CAAC,OAAO,CAAC,EAAE,IAAI;IAChD,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,CAAC;IAC9F,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE;QACV,EAAE,EAAE,aAAQ;QACZ,OAAO,EAAE,uBAAa;QACtB,SAAS,EAAE,uBAAe;QAC1B,eAAe,EAAE,+CAAyB;QAC1C,aAAa,EAAE,mCAAmB;QAClC,cAAc,EAAE,qCAAoB;KACrC;CACF,CAAC;AAGF,0CAAoF;AACpF,MAAM,oCAAoC,GAAG,IAAA,2BAAa,EAAC;IACzD,OAAO,EAAE,6BAA6B;IACtC,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,UAAU,OAAsC,EAAE,EAAE,MAAM,EAAsB,EAAE,IAAI;QAC9F,IAAA,yCAA8B,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;CACF,CAAC,CAAC;AAEU,QAAA,aAAa,GAAkD;IAC1E,IAAI,EAAE,QAAQ;IACd,CAAC,oCAAoC,CAAC,OAAO,CAAC,EAAE,IAAI;IACpD,QAAQ,EAAE,EAAE;IACZ,oBAAoB,EAAE;QACpB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,QAAA,eAAe;KACvB;CACF,CAAC;AAGW,QAAA,cAAc,GAAG;IAE5B,2DAAqC;IAGrC,0BAAkB;IAClB,qCAA6B;IAG7B,sBAAiB;IACjB,gCAA2B;IAG3B,+CAA+B;IAC/B,gDAAgC;IAChC,qDAAqC;IAGrC,wDAAuC;IACvC,kDAAiC;IACjC,iDAAgC;IAGhC,+BAAqB;IAIrB,oCAAoC;IACpC,gCAAgC;CACjC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/caster-json-schema/index.ts"],"names":[],"mappings":";;;AACA,uEAAsE;AAItE,6BAAgF;AAChF,uCAAiE;AACjE,mCAA0H;AAC1H,+DAG+B;AAC/B,mDAKyB;AACzB,qDAK0B;AAG1B,MAAM,gCAAgC,GAAG,IAAA,2BAAa,EAAC;IACrD,OAAO,EAAE,yBAAyB;IAClC,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,UAAU,KAAsB,EAAE,EAAE,MAAM,EAAsB,EAAE,IAAI;QAE9E,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QACzC,IAAG,CAAC,SAAS;YAAE,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;QAC/C,IAAA,gCAAqB,EAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;CACF,CAAC,CAAC;AAEU,QAAA,eAAe,GAAoC;IAC9D,IAAI,EAAE,QAAQ;IACd,CAAC,gCAAgC,CAAC,OAAO,CAAC,EAAE,IAAI;IAChD,QAAQ,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,CAAC;IAC9F,oBAAoB,EAAE,KAAK;IAC3B,UAAU,EAAE;QACV,EAAE,EAAE,aAAQ;QACZ,OAAO,EAAE,uBAAa;QACtB,SAAS,EAAE,uBAAe;QAC1B,eAAe,EAAE,+CAAyB;QAC1C,aAAa,EAAE,mCAAmB;QAClC,cAAc,EAAE,qCAAoB;KACrC;CACF,CAAC;AAGF,0CAAoF;AACpF,MAAM,oCAAoC,GAAG,IAAA,2BAAa,EAAC;IACzD,OAAO,EAAE,6BAA6B;IACtC,IAAI,EAAE,QAAQ;IACd,QAAQ,EAAE,UAAU,OAAsC,EAAE,EAAE,MAAM,EAAsB,EAAE,IAAI;QAC9F,IAAA,yCAA8B,EAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAClD,CAAC;CACF,CAAC,CAAC;AAEU,QAAA,aAAa,GAAkD;IAC1E,IAAI,EAAE,QAAQ;IACd,CAAC,oCAAoC,CAAC,OAAO,CAAC,EAAE,IAAI;IACpD,QAAQ,EAAE,EAAE;IACZ,oBAAoB,EAAE;QACpB,IAAI,EAAE,OAAO;QACb,KAAK,EAAE,QAAA,eAAe;KACvB;CACF,CAAC;AAGW,QAAA,cAAc,GAAG;IAE5B,2DAAqC;IAGrC,0BAAkB;IAClB,mCAA2B;IAC3B,qCAA6B;IAG7B,sBAAiB;IACjB,gCAA2B;IAG3B,+CAA+B;IAC/B,gDAAgC;IAChC,qDAAqC;IAGrC,wDAAuC;IACvC,kDAAiC;IACjC,iDAAgC;IAGhC,+BAAqB;IAIrB,oCAAoC;IACpC,gCAAgC;CACjC,CAAC"}
@@ -8,7 +8,7 @@ function validateHumanInfo(humanInfo) {
8
8
  validateFriendlyString(humanInfo.author);
9
9
  (0, utils_1.validateURL)(humanInfo.url);
10
10
  if (humanInfo.image)
11
- (0, utils_1.validateURL)(humanInfo.image);
11
+ (0, utils_1.validateImageDataURI)(humanInfo.image);
12
12
  }
13
13
  function validateFriendlyString(value) {
14
14
  if (!value.trim())
@@ -1 +1 @@
1
- {"version":3,"file":"human.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/validate/human.ts"],"names":[],"mappings":";;;;AACA,mCAAsC;AAGtC,2BACE,SAAgE;IAEhE,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvC,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,IAAA,mBAAW,EAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAG,SAAS,CAAC,KAAK;QAAE,IAAA,mBAAW,EAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC;AAED,gCAAuC,KAAa;IAClD,IAAG,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAG,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC7D,IAAG,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAE5D,IAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IACvE,IAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACxF,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACtF,CAAC"}
1
+ {"version":3,"file":"human.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/validate/human.ts"],"names":[],"mappings":";;;;AACA,mCAA4D;AAG5D,2BACE,SAAgE;IAEhE,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACvC,sBAAsB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACzC,IAAA,mBAAW,EAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAG,SAAS,CAAC,KAAK;QAAE,IAAA,4BAAoB,EAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED,gCAAuC,KAAa;IAClD,IAAG,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IACxD,IAAG,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC7D,IAAG,KAAK,CAAC,MAAM,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAE5D,IAAG,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAC;IACvE,IAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACxF,IAAI,cAAc,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;AACtF,CAAC"}
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.IMAGE_DATA_URI_MAX_BYTES = void 0;
3
4
  exports.validateSha256 = validateSha256;
4
5
  exports.validateURL = validateURL;
6
+ exports.validateImageDataURI = validateImageDataURI;
5
7
  function validateSha256(value) {
6
8
  if (/^[0-9a-f]{64}$/i.test(value))
7
9
  return;
@@ -20,4 +22,27 @@ function validateURL(value) {
20
22
  if (!["https:"].includes(url.protocol))
21
23
  throw new Error(`${value} is not a valid https`);
22
24
  }
25
+ const IMAGE_DATA_URI_PATTERN = /^data:image\/(png|jpeg|jpg|gif|webp|svg\+xml);base64,([A-Za-z0-9+/]+=*)$/;
26
+ exports.IMAGE_DATA_URI_MAX_BYTES = 64 * 1024;
27
+ const UNSAFE_SVG_CONTENT_PATTERN = /<\s*script\b|<\s*iframe\b|<\s*embed\b|<\s*object\b|<\s*foreignobject\b|on[a-z]+\s*=|javascript:/i;
28
+ function validateImageDataURI(value) {
29
+ const match = IMAGE_DATA_URI_PATTERN.exec(value);
30
+ if (!match)
31
+ throw new Error(`${value.slice(0, 32)}... is not a valid "data:image/<type>;base64,..." URI`);
32
+ const [, mimeSubtype, base64Data] = match;
33
+ const decodedByteLength = Math.floor(base64Data.length * 3 / 4) - (base64Data.match(/=+$/)?.[0].length ?? 0);
34
+ if (decodedByteLength > exports.IMAGE_DATA_URI_MAX_BYTES) {
35
+ throw new Error(`Embedded image is ${decodedByteLength} bytes, which exceeds the ${exports.IMAGE_DATA_URI_MAX_BYTES}-byte limit`);
36
+ }
37
+ if (mimeSubtype === "svg+xml") {
38
+ const svgText = base64ToUtf8(base64Data);
39
+ if (UNSAFE_SVG_CONTENT_PATTERN.test(svgText)) {
40
+ throw new Error("Embedded SVG must not contain scripts, event handler attributes, or embedded documents");
41
+ }
42
+ }
43
+ }
44
+ function base64ToUtf8(base64) {
45
+ const bytes = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
46
+ return new TextDecoder("utf-8").decode(bytes);
47
+ }
23
48
  //# sourceMappingURL=utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/validate/utils.ts"],"names":[],"mappings":";;;;AACA,wBAA+B,KAAa;IAE1C,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO;IAC1C,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAC;AACnE,CAAC;AAED,qBAA4B,KAAa;IACvC,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IACjD,CAAC;IACD,IAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW;QAAE,OAAO;IACpE,IAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uBAAuB,CAAC,CAAC;AAC1F,CAAC"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../../../../../src/match-lock-file/match-config/version-1/lock/rosters/validate/utils.ts"],"names":[],"mappings":";;;;;;AACA,wBAA+B,KAAa;IAE1C,IAAI,iBAAiB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO;IAC1C,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uCAAuC,CAAC,CAAC;AACnE,CAAC;AAED,qBAA4B,KAAa;IACvC,IAAI,GAAQ,CAAC;IACb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,qBAAqB,CAAC,CAAC;IACjD,CAAC;IACD,IAAG,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW;QAAE,OAAO;IACpE,IAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,uBAAuB,CAAC,CAAC;AAC1F,CAAC;AAED,MAAM,sBAAsB,GAAG,0EAA0E,CAAC;AAC7F,QAAA,wBAAwB,GAAG,EAAE,GAAG,IAAI,CAAC;AAKlD,MAAM,0BAA0B,GAAG,kGAAkG,CAAC;AAEtI,8BAAqC,KAAa;IAChD,MAAM,KAAK,GAAG,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACjD,IAAG,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,uDAAuD,CAAC,CAAC;IAEzG,MAAM,CAAC,EAAE,WAAW,EAAE,UAAU,CAAC,GAAG,KAAK,CAAC;IAC1C,MAAM,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC;IAC7G,IAAG,iBAAiB,GAAG,QAAA,wBAAwB,EAAC,CAAC;QAC/C,MAAM,IAAI,KAAK,CACb,qBAAqB,iBAAiB,6BAA6B,QAAA,wBAAwB,aAAa,CACzG,CAAC;IACJ,CAAC;IAED,IAAG,WAAW,KAAK,SAAS,EAAC,CAAC;QAC5B,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;QACzC,IAAG,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC,EAAC,CAAC;YAC3C,MAAM,IAAI,KAAK,CAAC,wFAAwF,CAAC,CAAC;QAC5G,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,YAAY,CAAC,MAAc;IAClC,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,OAAO,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChD,CAAC"}
@@ -8,6 +8,7 @@ const json_schema_1 = require("../../../util-types/json-schema");
8
8
  function ignore() { return true; }
9
9
  exports.rosterLockPieceInfoKeywords = [
10
10
  human_1.urlSchemaValidator,
11
+ human_1.imageDataURISchemaValidator,
11
12
  human_1.friendlyStringSchemaValidator,
12
13
  downloadableSources_1.downloadableSourceListSchemaValidator,
13
14
  (0, json_schema_1.defineKeyword)({
@@ -1 +1 @@
1
- {"version":3,"file":"keywords.js","sourceRoot":"","sources":["../../../../../src/match-lock-file/match-config/version-1/piece-info/keywords.ts"],"names":[],"mappings":";;;AACA,oEAGkD;AAClD,gGAEgE;AAChE,oFAI0D;AAE1D,iEAAgE;AAEhE,SAAS,MAAM,KAAI,OAAO,IAAI,CAAC,CAAC,CAAC;AAEpB,QAAA,2BAA2B,GAAG;IACzC,0BAAkB;IAClB,qCAA6B;IAE7B,2DAAqC;IACrC,IAAA,2BAAa,EAAC;QACZ,OAAO,EAAE,+CAA+B,CAAC,OAAO;QAChD,IAAI,EAAE,+CAA+B,CAAC,IAAI;QAC1C,QAAQ,EAAE,MAAM;KACjB,CAAC;IACF,IAAA,2BAAa,EAAC;QACZ,OAAO,EAAE,gDAAgC,CAAC,OAAO;QACjD,IAAI,EAAE,gDAAgC,CAAC,IAAI;QAC3C,QAAQ,EAAE,MAAM;KACjB,CAAC;IACF,IAAA,2BAAa,EAAC;QACZ,OAAO,EAAE,qDAAqC,CAAC,OAAO;QACtD,IAAI,EAAE,qDAAqC,CAAC,IAAI;QAChD,QAAQ,EAAE,MAAM;KACjB,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"keywords.js","sourceRoot":"","sources":["../../../../../src/match-lock-file/match-config/version-1/piece-info/keywords.ts"],"names":[],"mappings":";;;AACA,oEAIkD;AAClD,gGAEgE;AAChE,oFAI0D;AAE1D,iEAAgE;AAEhE,SAAS,MAAM,KAAI,OAAO,IAAI,CAAC,CAAC,CAAC;AAEpB,QAAA,2BAA2B,GAAG;IACzC,0BAAkB;IAClB,mCAA2B;IAC3B,qCAA6B;IAE7B,2DAAqC;IACrC,IAAA,2BAAa,EAAC;QACZ,OAAO,EAAE,+CAA+B,CAAC,OAAO;QAChD,IAAI,EAAE,+CAA+B,CAAC,IAAI;QAC1C,QAAQ,EAAE,MAAM;KACjB,CAAC;IACF,IAAA,2BAAa,EAAC;QACZ,OAAO,EAAE,gDAAgC,CAAC,OAAO;QACjD,IAAI,EAAE,gDAAgC,CAAC,IAAI;QAC3C,QAAQ,EAAE,MAAM;KACjB,CAAC;IACF,IAAA,2BAAa,EAAC;QACZ,OAAO,EAAE,qDAAqC,CAAC,OAAO;QACtD,IAAI,EAAE,qDAAqC,CAAC,IAAI;QAChD,QAAQ,EAAE,MAAM;KACjB,CAAC;CACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roster-lock/shared",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Shared utilities, variables, etc between client and server",
5
5
  "keywords": [
6
6
  "roster-lock",
@@ -39,7 +39,7 @@
39
39
  "magnet-uri": "^7.0.7",
40
40
  "micromatch": "^4.0.8",
41
41
  "runtypes": "^7.0.4",
42
- "@roster-lock/types": "1.0.0",
42
+ "@roster-lock/types": "1.1.0",
43
43
  "@roster-lock/utils": "1.0.0"
44
44
  },
45
45
  "scripts": {
@@ -4,13 +4,19 @@ type RosterLockPiece = RosterLockV1Config["rosters"][string][number];
4
4
  import { defineKeyword } from "../../../../../util-types/json-schema";
5
5
 
6
6
 
7
- import { validateURL } from "../validate";
7
+ import { validateURL, validateImageDataURI } from "../validate";
8
8
  export const urlSchemaValidator = defineKeyword({
9
9
  keyword: "URL",
10
10
  type: "string",
11
11
  validate: validateURL
12
12
  });
13
13
 
14
+ export const imageDataURISchemaValidator = defineKeyword({
15
+ keyword: "imageDataURI",
16
+ type: "string",
17
+ validate: validateImageDataURI
18
+ });
19
+
14
20
  import { validateFriendlyString } from "../validate/human";
15
21
  export const friendlyStringSchemaValidator = defineKeyword({
16
22
  keyword: "friendlyString",
@@ -27,7 +33,7 @@ export const humanInfoSchema: JSONSchemaType<RosterLockPiece["humanInfo"]> = {
27
33
  name: { type: "string", [friendlyStringSchemaValidator.keyword]: true },
28
34
  author: { type: "string", [friendlyStringSchemaValidator.keyword]: true },
29
35
  url: { type: "string", [urlSchemaValidator.keyword]: true },
30
- image: { type: "string", [urlSchemaValidator.keyword]: true, nullable: true },
36
+ image: { type: "string", [imageDataURISchemaValidator.keyword]: true, nullable: true },
31
37
  },
32
38
  }
33
39
 
@@ -5,7 +5,7 @@ type RosterLockPiece = RosterLockV1Config["rosters"][string][number];
5
5
 
6
6
  import { idSchema, idUniquenessSchemaValidator, idSchemaValidator } from "./id";
7
7
  import { versionSchema, sha256SchemaValidator } from "./version";
8
- import { humanInfoSchema, urlSchemaValidator, friendlyStringSchemaValidator } from "./human";
8
+ import { humanInfoSchema, urlSchemaValidator, imageDataURISchemaValidator, friendlyStringSchemaValidator } from "./human";
9
9
  import {
10
10
  downloadableSourcesSchema,
11
11
  downloadableSourceListSchemaValidator,
@@ -77,6 +77,7 @@ export const rosterKeywords = [
77
77
 
78
78
  // Human Related
79
79
  urlSchemaValidator,
80
+ imageDataURISchemaValidator,
80
81
  friendlyStringSchemaValidator,
81
82
 
82
83
  // Id Related
@@ -1,5 +1,5 @@
1
1
  import { RosterLockV1Config } from "@roster-lock/types";
2
- import { validateURL } from "./utils";
2
+ import { validateURL, validateImageDataURI } from "./utils";
3
3
 
4
4
 
5
5
  export function validateHumanInfo(
@@ -8,7 +8,7 @@ export function validateHumanInfo(
8
8
  validateFriendlyString(humanInfo.name);
9
9
  validateFriendlyString(humanInfo.author);
10
10
  validateURL(humanInfo.url);
11
- if(humanInfo.image) validateURL(humanInfo.image);
11
+ if(humanInfo.image) validateImageDataURI(humanInfo.image);
12
12
  }
13
13
 
14
14
  export function validateFriendlyString(value: string){
@@ -15,3 +15,36 @@ export function validateURL(value: string){
15
15
  if(url.protocol === "http:" && url.hostname === "localhost") return;
16
16
  if(!["https:"].includes(url.protocol)) throw new Error(`${value} is not a valid https`);
17
17
  }
18
+
19
+ const IMAGE_DATA_URI_PATTERN = /^data:image\/(png|jpeg|jpg|gif|webp|svg\+xml);base64,([A-Za-z0-9+/]+=*)$/;
20
+ export const IMAGE_DATA_URI_MAX_BYTES = 64 * 1024;
21
+
22
+ // Scripts/event handlers wouldn't execute from an <img src="data:...">, but pieces can
23
+ // come from third-party downloadSources - reject anything that would be dangerous if a
24
+ // future consumer ever rendered the SVG a different way (e.g. inline in the DOM).
25
+ const UNSAFE_SVG_CONTENT_PATTERN = /<\s*script\b|<\s*iframe\b|<\s*embed\b|<\s*object\b|<\s*foreignobject\b|on[a-z]+\s*=|javascript:/i;
26
+
27
+ export function validateImageDataURI(value: string){
28
+ const match = IMAGE_DATA_URI_PATTERN.exec(value);
29
+ if(!match) throw new Error(`${value.slice(0, 32)}... is not a valid "data:image/<type>;base64,..." URI`);
30
+
31
+ const [, mimeSubtype, base64Data] = match;
32
+ const decodedByteLength = Math.floor(base64Data.length * 3 / 4) - (base64Data.match(/=+$/)?.[0].length ?? 0);
33
+ if(decodedByteLength > IMAGE_DATA_URI_MAX_BYTES){
34
+ throw new Error(
35
+ `Embedded image is ${decodedByteLength} bytes, which exceeds the ${IMAGE_DATA_URI_MAX_BYTES}-byte limit`
36
+ );
37
+ }
38
+
39
+ if(mimeSubtype === "svg+xml"){
40
+ const svgText = base64ToUtf8(base64Data);
41
+ if(UNSAFE_SVG_CONTENT_PATTERN.test(svgText)){
42
+ throw new Error("Embedded SVG must not contain scripts, event handler attributes, or embedded documents");
43
+ }
44
+ }
45
+ }
46
+
47
+ function base64ToUtf8(base64: string): string {
48
+ const bytes = Uint8Array.from(atob(base64), (c) => c.charCodeAt(0));
49
+ return new TextDecoder("utf-8").decode(bytes);
50
+ }
@@ -1,6 +1,7 @@
1
1
 
2
2
  import {
3
3
  urlSchemaValidator,
4
+ imageDataURISchemaValidator,
4
5
  friendlyStringSchemaValidator,
5
6
  } from "../lock/rosters/caster-json-schema/human";
6
7
  import {
@@ -18,6 +19,7 @@ function ignore(){ return true; }
18
19
 
19
20
  export const rosterLockPieceInfoKeywords = [
20
21
  urlSchemaValidator,
22
+ imageDataURISchemaValidator,
21
23
  friendlyStringSchemaValidator,
22
24
 
23
25
  downloadableSourceListSchemaValidator,