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
@@ -0,0 +1,140 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert';
3
+ import { buildStatement } from './protocol';
4
+ import {
5
+ generateFileHash,
6
+ validateFileHash,
7
+ generateStatementContentHash,
8
+ validateStatementContentHash,
9
+ generateStatementHash,
10
+ validateStatementHash,
11
+ generateStatementsFile,
12
+ parseStatementsFile,
13
+ generateStatementFilename,
14
+ generateAttachmentFilename,
15
+ } from './utils';
16
+
17
+ describe('Statement Utils', () => {
18
+ const testContent = 'test content';
19
+ const testFileContent = Buffer.from('test file content');
20
+
21
+ describe('File Hash Functions', () => {
22
+ it('should generate file hash', () => {
23
+ const hash = generateFileHash(testFileContent);
24
+ assert.ok(hash);
25
+ assert.strictEqual(typeof hash, 'string');
26
+ });
27
+
28
+ it('should validate file hash', () => {
29
+ const hash = generateFileHash(testFileContent);
30
+ assert.strictEqual(validateFileHash(testFileContent, hash), true);
31
+ assert.strictEqual(validateFileHash(testFileContent, 'invalid-hash'), false);
32
+ });
33
+
34
+ it('should generate attachment filename', () => {
35
+ const filename = generateAttachmentFilename(testFileContent, 'pdf');
36
+ assert.ok(/^[A-Za-z0-9_-]+\.pdf$/.test(filename));
37
+ });
38
+
39
+ it('should handle extension with dot', () => {
40
+ const filename = generateAttachmentFilename(testFileContent, '.jpg');
41
+ assert.ok(/^[A-Za-z0-9_-]+\.jpg$/.test(filename));
42
+ });
43
+ });
44
+
45
+ describe('Statement Content Hash Functions', () => {
46
+ it('should generate statement content hash', () => {
47
+ const hash = generateStatementContentHash(testContent);
48
+ assert.ok(hash);
49
+ assert.strictEqual(typeof hash, 'string');
50
+ });
51
+
52
+ it('should validate statement content hash', () => {
53
+ const hash = generateStatementContentHash(testContent);
54
+ assert.strictEqual(validateStatementContentHash(testContent, hash), true);
55
+ assert.strictEqual(validateStatementContentHash(testContent, 'invalid-hash'), false);
56
+ });
57
+ });
58
+
59
+ describe('Statement Hash Functions', () => {
60
+ const statement = buildStatement({
61
+ domain: 'example.com',
62
+ author: 'Test Author',
63
+ time: new Date('2023-06-15T20:01:26.000Z'),
64
+ content: 'Test statement content',
65
+ });
66
+
67
+ it('should generate statement hash', () => {
68
+ const hash = generateStatementHash(statement);
69
+ assert.ok(hash);
70
+ assert.strictEqual(typeof hash, 'string');
71
+ });
72
+
73
+ it('should validate statement hash', () => {
74
+ const hash = generateStatementHash(statement);
75
+ assert.strictEqual(validateStatementHash(statement, hash), true);
76
+ assert.strictEqual(validateStatementHash(statement, 'invalid-hash'), false);
77
+ });
78
+
79
+ it('should generate statement filename', () => {
80
+ const filename = generateStatementFilename(statement);
81
+ assert.ok(/^[A-Za-z0-9_-]+\.txt$/.test(filename));
82
+ });
83
+
84
+ it('should exclude signature fields from hash', () => {
85
+ const signedStatement =
86
+ statement +
87
+ '---\n' +
88
+ 'Statement hash: test-hash\n' +
89
+ 'Public key: test-key\n' +
90
+ 'Signature: test-signature\n' +
91
+ 'Algorithm: Ed25519\n';
92
+
93
+ const hash = generateStatementHash(signedStatement);
94
+ const hashWithoutSignature = generateStatementHash(statement);
95
+ assert.strictEqual(hash, hashWithoutSignature);
96
+ });
97
+ });
98
+
99
+ describe('Statements File Functions', () => {
100
+ const statement1 = buildStatement({
101
+ domain: 'example.com',
102
+ author: 'Test Author',
103
+ time: new Date('2023-06-15T20:01:26.000Z'),
104
+ content: 'First statement',
105
+ });
106
+
107
+ const statement2 = buildStatement({
108
+ domain: 'example.com',
109
+ author: 'Test Author',
110
+ time: new Date('2023-06-16T10:30:00.000Z'),
111
+ content: 'Second statement',
112
+ });
113
+
114
+ it('should generate statements file', () => {
115
+ const statementsFile = generateStatementsFile([statement1, statement2]);
116
+ assert.ok(statementsFile.includes(statement1));
117
+ assert.ok(statementsFile.includes(statement2));
118
+ assert.ok(statementsFile.includes('\n\n'));
119
+ });
120
+
121
+ it('should parse statements file', () => {
122
+ const statementsFile = generateStatementsFile([statement1, statement2]);
123
+ const parsed = parseStatementsFile(statementsFile);
124
+ assert.strictEqual(parsed.length, 2);
125
+ assert.strictEqual(parsed[0], statement1);
126
+ assert.strictEqual(parsed[1], statement2);
127
+ });
128
+
129
+ it('should throw error for invalid statement in file', () => {
130
+ const invalidFile = 'Invalid statement\n\nAnother invalid statement';
131
+ assert.throws(() => parseStatementsFile(invalidFile));
132
+ });
133
+
134
+ it('should filter empty statements', () => {
135
+ const fileWithEmpty = statement1 + '\n\n\n\n' + statement2;
136
+ const parsed = parseStatementsFile(fileWithEmpty);
137
+ assert.strictEqual(parsed.length, 2);
138
+ });
139
+ });
140
+ });
package/src/utils.ts ADDED
@@ -0,0 +1,104 @@
1
+ import { peopleCountBuckets } from './constants';
2
+
3
+ import { sha256, verify } from './hash';
4
+ import { parseStatement } from './protocol';
5
+
6
+ export const generateFileHash = (fileContent: Buffer | string): string => {
7
+ return sha256(fileContent);
8
+ };
9
+
10
+ export const validateFileHash = (fileContent: Buffer | string, expectedHash: string): boolean => {
11
+ return verify(fileContent, expectedHash);
12
+ };
13
+
14
+ export const generateStatementContentHash = (statementContent: string): string => {
15
+ return sha256(statementContent);
16
+ };
17
+
18
+ export const validateStatementContentHash = (
19
+ statementContent: string,
20
+ expectedHash: string
21
+ ): boolean => {
22
+ return verify(statementContent, expectedHash);
23
+ };
24
+
25
+ export const generateStatementHash = (statement: string): string => {
26
+ const signatureRegex = /^([\s\S]+?)---\n[\s\S]+$/;
27
+ const match = statement.match(signatureRegex);
28
+
29
+ if (match && match[1]) {
30
+ return sha256(match[1]);
31
+ }
32
+
33
+ return sha256(statement);
34
+ };
35
+
36
+ export const validateStatementHash = (statement: string, expectedHash: string): boolean => {
37
+ const computedHash = generateStatementHash(statement);
38
+ return computedHash === expectedHash;
39
+ };
40
+
41
+ export const generateStatementsFile = (statements: string[]): string => {
42
+ return statements.join('\n\n');
43
+ };
44
+
45
+ export const parseStatementsFile = (statementsFileContent: string): string[] => {
46
+ const statementParts = statementsFileContent.split(/\n\nStated protocol version: /);
47
+ const statements: string[] = [];
48
+
49
+ for (let i = 0; i < statementParts.length; i++) {
50
+ let statement = statementParts[i];
51
+
52
+ if (i === 0 && statement.trim().length === 0) continue;
53
+
54
+ if (i > 0) {
55
+ statement = 'Stated protocol version: ' + statement;
56
+ }
57
+
58
+ statement = statement.replace(/\n+$/, '\n');
59
+
60
+ try {
61
+ parseStatement({ statement });
62
+ statements.push(statement);
63
+ } catch (error) {
64
+ throw new Error(
65
+ `Invalid statement at index ${i}: ${error instanceof Error ? error.message : String(error)}`
66
+ );
67
+ }
68
+ }
69
+
70
+ return statements;
71
+ };
72
+
73
+ export const generateStatementFilename = (statement: string): string => {
74
+ const hash = generateStatementHash(statement);
75
+ return `${hash}.txt`;
76
+ };
77
+
78
+ export const generateAttachmentFilename = (
79
+ fileContent: Buffer | string,
80
+ extension: string
81
+ ): string => {
82
+ const hash = generateFileHash(fileContent);
83
+ const ext = extension.startsWith('.') ? extension.substring(1) : extension;
84
+ return `${hash}.${ext}`;
85
+ };
86
+
87
+ export const minPeopleCountToRange = (n: number): string | undefined => {
88
+ if (n >= 10000000) return peopleCountBuckets['10000000'];
89
+ if (n >= 1000000) return peopleCountBuckets['1000000'];
90
+ if (n >= 100000) return peopleCountBuckets['100000'];
91
+ if (n >= 10000) return peopleCountBuckets['10000'];
92
+ if (n >= 1000) return peopleCountBuckets['1000'];
93
+ if (n >= 100) return peopleCountBuckets['100'];
94
+ if (n >= 10) return peopleCountBuckets['10'];
95
+ if (n >= 0) return peopleCountBuckets['0'];
96
+ };
97
+
98
+ export const monthIndex = (month: string): number =>
99
+ ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'].indexOf(
100
+ month.toLowerCase().substr(0, 3)
101
+ );
102
+
103
+ export const birthDateFormat: RegExp =
104
+ /(?<d>\d{1,2})\s(?<month>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(?<y>\d{4})/;