stated-protocol 5.0.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 (62) hide show
  1. package/README.md +409 -0
  2. package/dist/constants.d.ts +225 -0
  3. package/dist/constants.d.ts.map +1 -0
  4. package/dist/constants.js +227 -0
  5. package/dist/constants.js.map +1 -0
  6. package/dist/esm/constants.d.ts +225 -0
  7. package/dist/esm/constants.d.ts.map +1 -0
  8. package/dist/esm/hash.d.ts +37 -0
  9. package/dist/esm/hash.d.ts.map +1 -0
  10. package/dist/esm/index.d.ts +6 -0
  11. package/dist/esm/index.d.ts.map +1 -0
  12. package/dist/esm/index.js +2104 -0
  13. package/dist/esm/index.js.map +7 -0
  14. package/dist/esm/protocol.d.ts +30 -0
  15. package/dist/esm/protocol.d.ts.map +1 -0
  16. package/dist/esm/signature.d.ts +49 -0
  17. package/dist/esm/signature.d.ts.map +1 -0
  18. package/dist/esm/types.d.ts +115 -0
  19. package/dist/esm/types.d.ts.map +1 -0
  20. package/dist/esm/utils.d.ts +14 -0
  21. package/dist/esm/utils.d.ts.map +1 -0
  22. package/dist/hash.d.ts +37 -0
  23. package/dist/hash.d.ts.map +1 -0
  24. package/dist/hash.js +99 -0
  25. package/dist/hash.js.map +1 -0
  26. package/dist/index.d.ts +6 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +22 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/protocol.d.ts +30 -0
  31. package/dist/protocol.d.ts.map +1 -0
  32. package/dist/protocol.js +677 -0
  33. package/dist/protocol.js.map +1 -0
  34. package/dist/signature.d.ts +49 -0
  35. package/dist/signature.d.ts.map +1 -0
  36. package/dist/signature.js +169 -0
  37. package/dist/signature.js.map +1 -0
  38. package/dist/types.d.ts +115 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +30 -0
  41. package/dist/types.js.map +1 -0
  42. package/dist/utils.d.ts +14 -0
  43. package/dist/utils.d.ts.map +1 -0
  44. package/dist/utils.js +96 -0
  45. package/dist/utils.js.map +1 -0
  46. package/package.json +66 -0
  47. package/src/constants.ts +245 -0
  48. package/src/fixtures.test.ts +236 -0
  49. package/src/hash.test.ts +219 -0
  50. package/src/hash.ts +99 -0
  51. package/src/index.ts +5 -0
  52. package/src/organisation-verification.test.ts +50 -0
  53. package/src/person-verification.test.ts +55 -0
  54. package/src/poll.test.ts +28 -0
  55. package/src/protocol.ts +871 -0
  56. package/src/rating.test.ts +25 -0
  57. package/src/signature.test.ts +200 -0
  58. package/src/signature.ts +159 -0
  59. package/src/statement.test.ts +101 -0
  60. package/src/types.ts +185 -0
  61. package/src/utils.test.ts +140 -0
  62. package/src/utils.ts +104 -0
package/src/hash.ts ADDED
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Universal hash utilities using @noble/hashes
3
+ * Works in both browser and Node.js environments
4
+ */
5
+
6
+ import { sha256 as nobleSha256 } from '@noble/hashes/sha2.js';
7
+
8
+ /**
9
+ * Compute SHA-256 hash of a string and return it as URL-safe base64
10
+ * Works in both browser and Node.js environments
11
+ * @param input - The string or buffer to hash
12
+ * @returns URL-safe base64 encoded hash
13
+ */
14
+ export const sha256 = (input: string | Uint8Array): string => {
15
+ let data: Uint8Array;
16
+
17
+ if (typeof input === 'string') {
18
+ const encoder = new TextEncoder();
19
+ data = encoder.encode(input);
20
+ } else {
21
+ data = input;
22
+ }
23
+
24
+ // Use @noble/hashes for consistent cross-platform hashing
25
+ const hashArray = nobleSha256(data);
26
+
27
+ // Convert to base64
28
+ const base64 = bytesToBase64(hashArray);
29
+
30
+ // Make URL-safe: remove padding and replace + with - and / with _
31
+ const urlSafe = base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
32
+
33
+ return urlSafe;
34
+ };
35
+
36
+ /**
37
+ * Verify that content matches a given hash
38
+ * @param content - The content to verify
39
+ * @param hash - The expected hash
40
+ * @returns True if the hash matches
41
+ */
42
+ export const verify = (content: string | Uint8Array, hash: string): boolean => {
43
+ const computed = sha256(content);
44
+ return computed === hash;
45
+ };
46
+
47
+ /**
48
+ * Convert URL-safe base64 back to standard base64
49
+ * @param urlSafe - URL-safe base64 string
50
+ * @returns Standard base64 string with padding
51
+ */
52
+ export const fromUrlSafeBase64 = (urlSafe: string): string => {
53
+ const base64 = urlSafe.replace(/-/g, '+').replace(/_/g, '/');
54
+ // Add padding if needed
55
+ const padding = '='.repeat((4 - (base64.length % 4)) % 4);
56
+ return base64 + padding;
57
+ };
58
+
59
+ /**
60
+ * Convert standard base64 to URL-safe base64
61
+ * @param base64 - Standard base64 string
62
+ * @returns URL-safe base64 string without padding
63
+ */
64
+ export const toUrlSafeBase64 = (base64: string): string => {
65
+ return base64.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
66
+ };
67
+
68
+ /**
69
+ * Convert bytes to base64 string
70
+ * @param bytes - Uint8Array to convert
71
+ * @returns Base64 string
72
+ */
73
+ function bytesToBase64(bytes: Uint8Array): string {
74
+ // Use btoa if available (browser), otherwise use Buffer (Node.js)
75
+ if (typeof btoa !== 'undefined') {
76
+ return btoa(String.fromCharCode(...Array.from(bytes)));
77
+ } else {
78
+ return Buffer.from(bytes).toString('base64');
79
+ }
80
+ }
81
+
82
+ /**
83
+ * Convert base64 string to bytes
84
+ * @param base64 - Base64 string to convert
85
+ * @returns Uint8Array
86
+ */
87
+ export function base64ToBytes(base64: string): Uint8Array {
88
+ // Use atob if available (browser), otherwise use Buffer (Node.js)
89
+ if (typeof atob !== 'undefined') {
90
+ const binaryString = atob(base64);
91
+ const bytes = new Uint8Array(binaryString.length);
92
+ for (let i = 0; i < binaryString.length; i++) {
93
+ bytes[i] = binaryString.charCodeAt(i);
94
+ }
95
+ return bytes;
96
+ } else {
97
+ return new Uint8Array(Buffer.from(base64, 'base64'));
98
+ }
99
+ }
package/src/index.ts ADDED
@@ -0,0 +1,5 @@
1
+ export * from './protocol';
2
+ export * from './hash';
3
+ export * from './signature';
4
+ export * from './constants';
5
+ export * from './types';
@@ -0,0 +1,50 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { parseOrganisationVerification, buildOrganisationVerificationContent } from './protocol';
4
+
5
+ const randomUnicodeString = () =>
6
+ Array.from({ length: 20 }, () => String.fromCharCode(Math.floor(Math.random() * 65536)))
7
+ .join('')
8
+ .replace(/[\n;>=<"''\\]/g, '');
9
+
10
+ describe('Organisation verification building', () => {
11
+ it('build & parse function compatibility: input=parse(build(input))', () => {
12
+ const [name, englishName, city, domain, foreignDomain, serialNumber, reliabilityPolicy] =
13
+ Array.from({ length: 7 }, randomUnicodeString);
14
+ const pictureHash = 'abc123_-XYZ.png';
15
+ const country = 'Germany';
16
+ const province = 'Bayern';
17
+ const legalForm = 'corporation';
18
+ const employeeCount = '100-1000';
19
+ const confidence = 0.8;
20
+ const verificationContent = buildOrganisationVerificationContent({
21
+ name,
22
+ englishName,
23
+ country,
24
+ city,
25
+ province,
26
+ legalForm,
27
+ domain,
28
+ pictureHash,
29
+ foreignDomain,
30
+ serialNumber,
31
+ confidence,
32
+ reliabilityPolicy,
33
+ employeeCount,
34
+ });
35
+ const parsedVerification = parseOrganisationVerification(verificationContent);
36
+ assert.strictEqual(parsedVerification.name, name);
37
+ assert.strictEqual(parsedVerification.englishName, englishName);
38
+ assert.strictEqual(parsedVerification.country, country);
39
+ assert.strictEqual(parsedVerification.city, city);
40
+ assert.strictEqual(parsedVerification.province, province);
41
+ assert.strictEqual(parsedVerification.legalForm, legalForm);
42
+ assert.strictEqual(parsedVerification.domain, domain);
43
+ assert.strictEqual(parsedVerification.foreignDomain, foreignDomain);
44
+ assert.strictEqual(parsedVerification.serialNumber, serialNumber);
45
+ assert.strictEqual(parsedVerification.confidence, confidence);
46
+ assert.strictEqual(parsedVerification.pictureHash, pictureHash);
47
+ assert.strictEqual(parsedVerification.reliabilityPolicy, reliabilityPolicy);
48
+ assert.strictEqual(parsedVerification.employeeCount, employeeCount);
49
+ });
50
+ });
@@ -0,0 +1,55 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { parsePersonVerification, buildPersonVerificationContent } from './protocol';
4
+
5
+ const randomUnicodeString = () =>
6
+ Array.from({ length: 20 }, () => String.fromCharCode(Math.floor(Math.random() * 65536)))
7
+ .join('')
8
+ .replace(/[\n;>=<"''\\]/g, '');
9
+
10
+ describe('Person verification building', () => {
11
+ it('build & parse function compatibility: input=parse(build(input))', () => {
12
+ const [
13
+ name,
14
+ ownDomain,
15
+ foreignDomain,
16
+ jobTitle,
17
+ employer,
18
+ verificationMethod,
19
+ picture,
20
+ reliabilityPolicy,
21
+ ] = Array.from({ length: 12 }, randomUnicodeString);
22
+ const countryOfBirth = 'Germany';
23
+ const cityOfBirth = 'Berlin';
24
+ const confidence = Math.random();
25
+ const dateOfBirth = new Date(0);
26
+ const personVerificationContent = buildPersonVerificationContent({
27
+ name,
28
+ countryOfBirth,
29
+ cityOfBirth,
30
+ ownDomain,
31
+ foreignDomain,
32
+ dateOfBirth,
33
+ jobTitle,
34
+ employer,
35
+ verificationMethod,
36
+ confidence,
37
+ picture,
38
+ reliabilityPolicy,
39
+ });
40
+
41
+ const parsedVerification = parsePersonVerification(personVerificationContent);
42
+ assert.strictEqual(parsedVerification.name, name);
43
+ assert.strictEqual(parsedVerification.ownDomain, ownDomain);
44
+ assert.strictEqual(parsedVerification.foreignDomain, foreignDomain);
45
+ assert.strictEqual(parsedVerification.dateOfBirth.toUTCString(), dateOfBirth.toUTCString());
46
+ assert.strictEqual(parsedVerification.jobTitle, jobTitle);
47
+ assert.strictEqual(parsedVerification.employer, employer);
48
+ assert.strictEqual(parsedVerification.verificationMethod, verificationMethod);
49
+ assert.strictEqual(parsedVerification.confidence, confidence);
50
+ assert.strictEqual(parsedVerification.picture, picture);
51
+ assert.strictEqual(parsedVerification.reliabilityPolicy, reliabilityPolicy);
52
+ assert.strictEqual(parsedVerification.countryOfBirth, countryOfBirth);
53
+ assert.strictEqual(parsedVerification.cityOfBirth, cityOfBirth);
54
+ });
55
+ });
@@ -0,0 +1,28 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { parsePoll, buildPollContent } from './protocol';
4
+
5
+ const randomUnicodeString = () =>
6
+ Array.from({ length: 20 }, () => String.fromCharCode(Math.floor(Math.random() * 65536)))
7
+ .join('')
8
+ .replace(/[\n;>=<"''\\]/g, '');
9
+
10
+ describe('Poll building', () => {
11
+ it('build & parse function compatibility: input=parse(build(input))', () => {
12
+ const [poll, scopeDescription] = Array.from({ length: 2 }, randomUnicodeString);
13
+ const options = Array.from({ length: 2 }, randomUnicodeString);
14
+ const deadline = new Date('Thu, 01 Dec 2022 13:38:26 GMT');
15
+ const pollContent = buildPollContent({
16
+ deadline,
17
+ poll,
18
+ options,
19
+ scopeDescription,
20
+ });
21
+ const parsedPoll = parsePoll(pollContent, '5');
22
+ assert.strictEqual(parsedPoll.poll, poll);
23
+ assert.strictEqual(parsedPoll.scopeDescription, scopeDescription);
24
+ assert.strictEqual(parsedPoll.deadline?.toUTCString(), deadline.toUTCString());
25
+ assert.strictEqual(parsedPoll.options[0], options[0]);
26
+ assert.strictEqual(parsedPoll.options[1], options[1]);
27
+ });
28
+ });