stated-protocol-parser 1.0.7 → 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.
- package/README.md +231 -22
- package/dist/constants.d.ts +193 -15
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +197 -20
- package/dist/constants.js.map +1 -1
- package/dist/esm/constants.d.ts +193 -15
- package/dist/esm/constants.d.ts.map +1 -1
- package/dist/esm/{hash.browser.d.ts → hash.d.ts} +11 -5
- package/dist/esm/hash.d.ts.map +1 -0
- package/dist/esm/index.d.ts +4 -42
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2102 -641
- package/dist/esm/index.js.map +7 -1
- package/dist/esm/protocol.d.ts +18 -30
- package/dist/esm/protocol.d.ts.map +1 -1
- package/dist/esm/signature.d.ts +49 -0
- package/dist/esm/signature.d.ts.map +1 -0
- package/dist/esm/types.d.ts +26 -60
- package/dist/esm/types.d.ts.map +1 -1
- package/dist/esm/utils.d.ts +10 -0
- package/dist/esm/utils.d.ts.map +1 -1
- package/dist/{hash.browser.d.ts → hash.d.ts} +11 -5
- package/dist/hash.d.ts.map +1 -0
- package/dist/{hash.browser.js → hash.js} +44 -10
- package/dist/hash.js.map +1 -0
- package/dist/index.d.ts +4 -42
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -674
- package/dist/index.js.map +1 -1
- package/dist/protocol.d.ts +18 -30
- package/dist/protocol.d.ts.map +1 -1
- package/dist/protocol.js +565 -572
- package/dist/protocol.js.map +1 -1
- package/dist/signature.d.ts +49 -0
- package/dist/signature.d.ts.map +1 -0
- package/dist/signature.js +169 -0
- package/dist/signature.js.map +1 -0
- package/dist/types.d.ts +26 -60
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +10 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +79 -11
- package/dist/utils.js.map +1 -1
- package/package.json +32 -27
- package/src/constants.ts +228 -44
- package/src/fixtures.test.ts +236 -0
- package/src/hash.test.ts +217 -215
- package/src/hash.ts +99 -0
- package/src/index.ts +5 -0
- package/src/organisation-verification.test.ts +50 -0
- package/src/person-verification.test.ts +55 -0
- package/src/poll.test.ts +28 -0
- package/src/protocol.ts +855 -650
- package/src/rating.test.ts +25 -0
- package/src/signature.test.ts +200 -0
- package/src/signature.ts +159 -0
- package/src/statement.test.ts +101 -0
- package/src/types.ts +155 -156
- package/src/utils.test.ts +140 -0
- package/src/utils.ts +102 -16
- package/dist/esm/constants.js +0 -47
- package/dist/esm/constants.js.map +0 -1
- package/dist/esm/hash.browser.d.ts.map +0 -1
- package/dist/esm/hash.browser.js +0 -58
- package/dist/esm/hash.browser.js.map +0 -1
- package/dist/esm/hash.node.d.ts +0 -31
- package/dist/esm/hash.node.d.ts.map +0 -1
- package/dist/esm/hash.node.js +0 -43
- package/dist/esm/hash.node.js.map +0 -1
- package/dist/esm/hash.test.d.ts +0 -2
- package/dist/esm/hash.test.d.ts.map +0 -1
- package/dist/esm/hash.test.js +0 -181
- package/dist/esm/hash.test.js.map +0 -1
- package/dist/esm/index.browser.d.ts +0 -3
- package/dist/esm/index.browser.d.ts.map +0 -1
- package/dist/esm/index.browser.js +0 -5
- package/dist/esm/index.browser.js.map +0 -1
- package/dist/esm/index.node.d.ts +0 -3
- package/dist/esm/index.node.d.ts.map +0 -1
- package/dist/esm/index.node.js +0 -5
- package/dist/esm/index.node.js.map +0 -1
- package/dist/esm/index.test.d.ts +0 -2
- package/dist/esm/index.test.d.ts.map +0 -1
- package/dist/esm/index.test.js +0 -293
- package/dist/esm/index.test.js.map +0 -1
- package/dist/esm/protocol.js +0 -639
- package/dist/esm/protocol.js.map +0 -1
- package/dist/esm/types.js +0 -2
- package/dist/esm/types.js.map +0 -1
- package/dist/esm/utils.js +0 -23
- package/dist/esm/utils.js.map +0 -1
- package/dist/esm/v3.d.ts +0 -5
- package/dist/esm/v3.d.ts.map +0 -1
- package/dist/esm/v3.js +0 -60
- package/dist/esm/v3.js.map +0 -1
- package/dist/hash.browser.d.ts.map +0 -1
- package/dist/hash.browser.js.map +0 -1
- package/dist/hash.node.d.ts +0 -31
- package/dist/hash.node.d.ts.map +0 -1
- package/dist/hash.node.js +0 -53
- package/dist/hash.node.js.map +0 -1
- package/dist/hash.test.d.ts +0 -2
- package/dist/hash.test.d.ts.map +0 -1
- package/dist/hash.test.js +0 -183
- package/dist/hash.test.js.map +0 -1
- package/dist/index.browser.d.ts +0 -3
- package/dist/index.browser.d.ts.map +0 -1
- package/dist/index.browser.js +0 -21
- package/dist/index.browser.js.map +0 -1
- package/dist/index.node.d.ts +0 -3
- package/dist/index.node.d.ts.map +0 -1
- package/dist/index.node.js +0 -21
- package/dist/index.node.js.map +0 -1
- package/dist/index.test.d.ts +0 -2
- package/dist/index.test.d.ts.map +0 -1
- package/dist/index.test.js +0 -295
- package/dist/index.test.js.map +0 -1
- package/dist/v3.d.ts +0 -5
- package/dist/v3.d.ts.map +0 -1
- package/dist/v3.js +0 -64
- package/dist/v3.js.map +0 -1
- package/src/hash.browser.ts +0 -65
- package/src/hash.node.ts +0 -47
- package/src/index.browser.ts +0 -4
- package/src/index.node.ts +0 -4
- package/src/index.test.ts +0 -378
- package/src/v3.ts +0 -62
package/dist/protocol.js
CHANGED
|
@@ -14,671 +14,664 @@ 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
|
-
exports.
|
|
18
|
-
/* eslint-disable no-useless-concat */
|
|
17
|
+
exports.parseRating = exports.buildRating = exports.parsePDFSigning = exports.buildPDFSigningContent = exports.parseResponseContent = exports.buildResponseContent = exports.parseDisputeContent = exports.buildDisputeContentContent = exports.parseDisputeAuthenticity = exports.buildDisputeAuthenticityContent = exports.parseVote = exports.buildVoteContent = exports.parsePersonVerification = exports.buildPersonVerificationContent = exports.parseOrganisationVerification = exports.buildOrganisationVerificationContent = exports.parsePoll = exports.buildPollContent = exports.parseStatement = exports.buildStatement = void 0;
|
|
19
18
|
const constants_1 = require("./constants");
|
|
20
|
-
const v3_1 = require("./v3");
|
|
21
19
|
const utils_1 = require("./utils");
|
|
22
|
-
const
|
|
23
|
-
const
|
|
20
|
+
const signature_1 = require("./signature");
|
|
21
|
+
const hash_1 = require("./hash");
|
|
22
|
+
const types_1 = require("./types");
|
|
23
|
+
const version = 5;
|
|
24
24
|
__exportStar(require("./types"), exports);
|
|
25
25
|
__exportStar(require("./constants"), exports);
|
|
26
26
|
__exportStar(require("./utils"), exports);
|
|
27
|
-
|
|
28
|
-
const buildStatement = ({ domain, author, time, tags, content, representative, supersededStatement }) => {
|
|
27
|
+
const buildStatement = ({ domain, author, time, tags, content, representative, supersededStatement, translations, attachments, }) => {
|
|
29
28
|
if (content.match(/\nPublishing domain: /))
|
|
30
|
-
throw
|
|
29
|
+
throw new Error("Statement must not contain 'Publishing domain: ', as this marks the beginning of a new statement.");
|
|
31
30
|
if (content.match(/\n\n/))
|
|
32
|
-
throw
|
|
31
|
+
throw new Error('Statement content must not contain two line breaks in a row, as this is used for separating statements.');
|
|
32
|
+
if (content.match(/\nTranslation [a-z]{2,3}:\n/))
|
|
33
|
+
throw new Error("Statement content must not contain 'Translation XX:\\n' pattern, as this is reserved for translations.");
|
|
34
|
+
if (content.match(/\nAttachments: /))
|
|
35
|
+
throw new Error("Statement content must not contain 'Attachments: ' on a new line, as this is reserved for file attachments.");
|
|
33
36
|
if (typeof time !== 'object' || !time.toUTCString)
|
|
34
|
-
throw
|
|
37
|
+
throw new Error('Time must be a Date object.');
|
|
35
38
|
if (!domain)
|
|
36
|
-
throw
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
39
|
+
throw new Error('Publishing domain missing.');
|
|
40
|
+
if (attachments && attachments.length > 5)
|
|
41
|
+
throw new Error('Maximum 5 attachments allowed.');
|
|
42
|
+
if (attachments) {
|
|
43
|
+
attachments.forEach((attachment, index) => {
|
|
44
|
+
if (!attachment.match(/^[A-Za-z0-9_-]+\.[a-zA-Z0-9]+$/)) {
|
|
45
|
+
throw new Error(`Attachment ${index + 1} must be in format 'base64hash.extension' (URL-safe base64)`);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (translations) {
|
|
50
|
+
for (const [lang, translation] of Object.entries(translations)) {
|
|
51
|
+
if (translation.match(/\nPublishing domain: /))
|
|
52
|
+
throw new Error(`Translation for ${lang} must not contain 'Publishing domain: '.`);
|
|
53
|
+
if (translation.match(/Translation [a-z]{2,3}:\n/))
|
|
54
|
+
throw new Error(`Translation for ${lang} must not contain 'Translation XX:\\n' pattern.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const translationLines = translations
|
|
58
|
+
? Object.entries(translations)
|
|
59
|
+
.map(([lang, translation]) => {
|
|
60
|
+
const translationWithNewline = translation + (translation.match(/\n$/) ? '' : '\n');
|
|
61
|
+
const indentedTranslation = translationWithNewline
|
|
62
|
+
.split('\n')
|
|
63
|
+
.map((line) => (line ? ' ' + line : line))
|
|
64
|
+
.join('\n');
|
|
65
|
+
return `Translation ${lang}:\n${indentedTranslation}`;
|
|
66
|
+
})
|
|
67
|
+
.join('')
|
|
68
|
+
: '';
|
|
69
|
+
const attachmentLines = attachments && attachments.length > 0 ? 'Attachments: ' + attachments.join(', ') + '\n' : '';
|
|
70
|
+
const contentWithNewline = content + (content.match(/\n$/) ? '' : '\n');
|
|
71
|
+
// Only indent plain content (non-typed statements). Typed statements already have indentation from build functions.
|
|
72
|
+
const isTypedContent = contentWithNewline.trim().startsWith('Type:');
|
|
73
|
+
const finalContent = isTypedContent
|
|
74
|
+
? contentWithNewline
|
|
75
|
+
: contentWithNewline
|
|
76
|
+
.split('\n')
|
|
77
|
+
.map((line) => (line ? ' ' + line : line))
|
|
78
|
+
.join('\n');
|
|
79
|
+
const statement = 'Stated protocol version: ' +
|
|
80
|
+
version +
|
|
81
|
+
'\n' +
|
|
82
|
+
'Publishing domain: ' +
|
|
83
|
+
domain +
|
|
84
|
+
'\n' +
|
|
85
|
+
'Author: ' +
|
|
86
|
+
(author || '') +
|
|
87
|
+
'\n' +
|
|
88
|
+
(representative && representative?.length > 0
|
|
89
|
+
? 'Authorized signing representative: ' + (representative || '') + '\n'
|
|
90
|
+
: '') +
|
|
91
|
+
'Time: ' +
|
|
92
|
+
time.toUTCString() +
|
|
93
|
+
'\n' +
|
|
94
|
+
(tags && tags.length > 0 ? 'Tags: ' + tags.join(', ') + '\n' : '') +
|
|
95
|
+
(supersededStatement && supersededStatement?.length > 0
|
|
96
|
+
? 'Superseded statement: ' + (supersededStatement || '') + '\n'
|
|
97
|
+
: '') +
|
|
98
|
+
'Statement content:\n' +
|
|
99
|
+
finalContent +
|
|
100
|
+
translationLines +
|
|
101
|
+
attachmentLines;
|
|
45
102
|
if (statement.length > 3000)
|
|
46
|
-
throw
|
|
103
|
+
throw new Error('Statement must not be longer than 3,000 characters.');
|
|
47
104
|
return statement;
|
|
48
105
|
};
|
|
49
106
|
exports.buildStatement = buildStatement;
|
|
50
|
-
const parseStatement = ({ statement:
|
|
51
|
-
if (
|
|
52
|
-
throw
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
107
|
+
const parseStatement = ({ statement: input, }) => {
|
|
108
|
+
if (input.length > 3000)
|
|
109
|
+
throw new Error('Statement must not be longer than 3,000 characters.');
|
|
110
|
+
const beforeTranslations = input.split(/\nTranslation [a-z]{2,3}:\n/)[0];
|
|
111
|
+
if (beforeTranslations.match(/\n\n/))
|
|
112
|
+
throw new Error('Statements cannot contain two line breaks in a row before translations, as this is used for separating statements.');
|
|
113
|
+
const signatureRegex = new RegExp('' +
|
|
114
|
+
/^(?<statement>[\s\S]+?)---\n/.source +
|
|
115
|
+
/Statement hash: (?<statementHash>[A-Za-z0-9_-]+)\n/.source +
|
|
116
|
+
/Public key: (?<publicKey>[A-Za-z0-9_-]+)\n/.source +
|
|
117
|
+
/Signature: (?<signature>[A-Za-z0-9_-]+)\n/.source +
|
|
118
|
+
/Algorithm: (?<algorithm>[^\n]+)\n/.source +
|
|
119
|
+
/$/.source);
|
|
120
|
+
const signatureMatch = input.match(signatureRegex);
|
|
121
|
+
let statementToVerify = input;
|
|
122
|
+
let publicKey;
|
|
123
|
+
let signature;
|
|
124
|
+
if (signatureMatch && signatureMatch.groups) {
|
|
125
|
+
statementToVerify = signatureMatch.groups.statement;
|
|
126
|
+
const statementHash = signatureMatch.groups.statementHash;
|
|
127
|
+
publicKey = signatureMatch.groups.publicKey;
|
|
128
|
+
signature = signatureMatch.groups.signature;
|
|
129
|
+
const algorithm = signatureMatch.groups.algorithm;
|
|
130
|
+
if (algorithm !== 'Ed25519') {
|
|
131
|
+
throw new Error('Unsupported signature algorithm: ' + algorithm);
|
|
132
|
+
}
|
|
133
|
+
const computedHash = (0, hash_1.sha256)(statementToVerify);
|
|
134
|
+
if (computedHash !== statementHash) {
|
|
135
|
+
throw new Error('Statement hash mismatch');
|
|
136
|
+
}
|
|
137
|
+
const isValid = (0, signature_1.verifySignature)(statementToVerify, signature, publicKey);
|
|
138
|
+
if (!isValid) {
|
|
139
|
+
throw new Error('Invalid cryptographic signature');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const statementRegex = new RegExp('' +
|
|
143
|
+
/^Stated protocol version: (?<formatVersion>[^\n]+?)\n/.source +
|
|
144
|
+
/Publishing domain: (?<domain>[^\n]+?)\n/.source +
|
|
145
|
+
/Author: (?<author>[^\n]+?)\n/.source +
|
|
146
|
+
/(?:Authorized signing representative: (?<representative>[^\n]*?)\n)?/.source +
|
|
147
|
+
/Time: (?<time>[^\n]+?)\n/.source +
|
|
148
|
+
/(?:Tags: (?<tags>[^\n]*?)\n)?/.source +
|
|
149
|
+
/(?:Superseded statement: (?<supersededStatement>[^\n]*?)\n)?/.source +
|
|
150
|
+
/Statement content:\n/.source +
|
|
151
|
+
/(?:(?<typedContent> Type: (?<type>[^\n]+?)\n[\s\S]+?)(?=\nTranslation [a-z]{2,3}:\n|Attachments: |$)|(?<content>(?: [\s\S]+?)?))/
|
|
152
|
+
.source +
|
|
153
|
+
/(?=\nTranslation [a-z]{2,3}:\n|Attachments: |$)/.source +
|
|
154
|
+
/(?<translations>(?:\nTranslation [a-z]{2,3}:\n[\s\S]+?)*)/.source +
|
|
155
|
+
/(?:Attachments: (?<attachments>[^\n]+?)\n)?/.source +
|
|
156
|
+
/$/.source);
|
|
157
|
+
const match = statementToVerify.match(statementRegex);
|
|
158
|
+
if (!match || !match.groups)
|
|
159
|
+
throw new Error('Invalid statement format: ' + input);
|
|
160
|
+
const { domain, author, representative, time: timeStr, tags: tagsStr, supersededStatement, attachments: attachmentsStr, formatVersion, content, typedContent, type, translations: translationsStr, } = match.groups;
|
|
161
|
+
const parsed = {
|
|
162
|
+
domain,
|
|
163
|
+
author,
|
|
164
|
+
representative,
|
|
165
|
+
timeStr,
|
|
166
|
+
tagsStr,
|
|
167
|
+
supersededStatement,
|
|
168
|
+
formatVersion,
|
|
169
|
+
content: content
|
|
170
|
+
? content
|
|
171
|
+
.split('\n')
|
|
172
|
+
.map((line) => (line.startsWith(' ') ? line.substring(4) : line))
|
|
173
|
+
.join('\n')
|
|
174
|
+
.replace(/\n$/, '')
|
|
175
|
+
: typedContent,
|
|
176
|
+
type: type ? type.toLowerCase().replace(' ', '_') : undefined,
|
|
177
|
+
translationsStr,
|
|
71
178
|
};
|
|
72
|
-
if (!
|
|
73
|
-
throw new Error(
|
|
74
|
-
if (!
|
|
75
|
-
throw new Error(
|
|
76
|
-
if (!
|
|
77
|
-
throw new Error(
|
|
78
|
-
if (!
|
|
79
|
-
throw new Error(
|
|
80
|
-
if (!
|
|
81
|
-
throw new Error(
|
|
82
|
-
|
|
83
|
-
|
|
179
|
+
if (!parsed.timeStr.match(constants_1.UTCFormat))
|
|
180
|
+
throw new Error('Invalid statement format: time must be in UTC');
|
|
181
|
+
if (!parsed.domain)
|
|
182
|
+
throw new Error('Invalid statement format: domain is required');
|
|
183
|
+
if (!parsed.author)
|
|
184
|
+
throw new Error('Invalid statement format: author is required');
|
|
185
|
+
if (!parsed.content)
|
|
186
|
+
throw new Error('Invalid statement format: statement content is required');
|
|
187
|
+
if (!parsed.formatVersion)
|
|
188
|
+
throw new Error('Invalid statement format: format version is required');
|
|
189
|
+
if (parsed.formatVersion !== '5')
|
|
190
|
+
throw new Error(`Invalid statement format: only version 5 is supported, got version ${parsed.formatVersion}`);
|
|
191
|
+
const tags = parsed.tagsStr?.split(', ');
|
|
192
|
+
const time = new Date(parsed.timeStr);
|
|
193
|
+
let attachments = undefined;
|
|
194
|
+
if (attachmentsStr && attachmentsStr.length > 0) {
|
|
195
|
+
attachments = attachmentsStr.split(', ').map((a) => a.trim());
|
|
196
|
+
if (attachments.length > 5) {
|
|
197
|
+
throw new Error('Maximum 5 attachments allowed');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
let translations = undefined;
|
|
201
|
+
if (parsed.translationsStr && parsed.translationsStr.length > 0) {
|
|
202
|
+
translations = {};
|
|
203
|
+
const translationParts = parsed.translationsStr
|
|
204
|
+
.split(/\nTranslation ([a-z]{2,3}):\n/)
|
|
205
|
+
.filter((part) => part.length > 0);
|
|
206
|
+
for (let i = 0; i < translationParts.length; i += 2) {
|
|
207
|
+
if (i + 1 < translationParts.length) {
|
|
208
|
+
const lang = translationParts[i];
|
|
209
|
+
const rawTranslation = translationParts[i + 1];
|
|
210
|
+
// Strip indentation from translation content
|
|
211
|
+
const translation = rawTranslation
|
|
212
|
+
.split('\n')
|
|
213
|
+
.map((line) => (line.startsWith(' ') ? line.substring(4) : line))
|
|
214
|
+
.join('\n')
|
|
215
|
+
.replace(/\n$/, '');
|
|
216
|
+
translations[lang] = translation;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
84
220
|
return {
|
|
85
|
-
domain:
|
|
86
|
-
author:
|
|
87
|
-
representative:
|
|
221
|
+
domain: parsed.domain,
|
|
222
|
+
author: parsed.author,
|
|
223
|
+
representative: parsed.representative,
|
|
88
224
|
time,
|
|
89
|
-
tags:
|
|
90
|
-
supersededStatement:
|
|
91
|
-
formatVersion:
|
|
92
|
-
content:
|
|
93
|
-
type:
|
|
225
|
+
tags: tags && tags.length > 0 ? tags : undefined,
|
|
226
|
+
supersededStatement: parsed.supersededStatement,
|
|
227
|
+
formatVersion: parsed.formatVersion,
|
|
228
|
+
content: parsed.content,
|
|
229
|
+
type: parsed.type?.toLowerCase().replace(' ', '_'),
|
|
230
|
+
translations: translations && Object.keys(translations).length > 0 ? translations : undefined,
|
|
231
|
+
attachments: attachments && attachments.length > 0 ? attachments : undefined,
|
|
94
232
|
};
|
|
95
233
|
};
|
|
96
234
|
exports.parseStatement = parseStatement;
|
|
97
|
-
const
|
|
98
|
-
if (quotation && quotation.match(/\n/))
|
|
99
|
-
throw (new Error("Quotation must not contain line breaks."));
|
|
100
|
-
if (!paraphrasedStatement && !quotation)
|
|
101
|
-
throw (new Error("Quotation must contain either a quotation or a paraphrased statement."));
|
|
102
|
-
const content = "\n" +
|
|
103
|
-
"\t" + "Type: Quotation" + "\n" +
|
|
104
|
-
"\t" + "Original author: " + originalAuthor + "\n" +
|
|
105
|
-
"\t" + "Author verification: " + authorVerification + "\n" +
|
|
106
|
-
(originalTime && originalTime?.length > 0 ? "\t" + "Original publication time: " + originalTime + "\n" : "") +
|
|
107
|
-
(source && source?.length > 0 ? "\t" + "Source: " + (source || "") + "\n" : '') +
|
|
108
|
-
(picture && picture.length > 0 ? "\t" + "Picture proof: " + (picture || "") + "\n" : '') +
|
|
109
|
-
(confidence && confidence?.length > 0 ? "\t" + "Confidence: " + (confidence || "") + "\n" : '') +
|
|
110
|
-
(quotation && quotation?.length > 0 ? "\t" + "Quotation: " + (quotation || "") + "\n" : '') +
|
|
111
|
-
(paraphrasedStatement && paraphrasedStatement?.length > 0 ? "\t" + "Paraphrased statement: " +
|
|
112
|
-
(paraphrasedStatement || "").replace(/\n\t([^\t])/, '\n\t\t($1)') + "\n" : '') +
|
|
113
|
-
"";
|
|
114
|
-
return content;
|
|
115
|
-
};
|
|
116
|
-
exports.buildQuotationContent = buildQuotationContent;
|
|
117
|
-
const parseQuotation = (s) => {
|
|
118
|
-
const voteRegex = new RegExp(''
|
|
119
|
-
+ /^\n\tType: Quotation\n/.source
|
|
120
|
-
+ /\tOriginal author: (?<originalAuthor>[^\n]+?)\n/.source
|
|
121
|
-
+ /\tAuthor verification: (?<authorVerification>[^\n]+?)\n/.source
|
|
122
|
-
+ /(?:\tOriginal publication time: (?<originalTime>[^\n]+?)\n)?/.source
|
|
123
|
-
+ /(?:\tSource: (?<source>[^\n]+?)\n)?/.source
|
|
124
|
-
+ /(?:\tPicture proof: (?<picture>[^\n]+?)\n)?/.source
|
|
125
|
-
+ /(?:\tConfidence: (?<confidence>[^\n]+?)\n)?/.source
|
|
126
|
-
+ /(?:\tQuotation: (?<quotation>[^\n]+?)\n)?/.source
|
|
127
|
-
+ /(?:\tParaphrased statement: (?:(?<paraphrasedTypedStatement>\n\t\tType: (?<type>[^\n]+?)\n[\s\S]+?)|(?<paraphrasedStatement>[\s\S]+?)))/.source
|
|
128
|
-
+ /$/.source);
|
|
129
|
-
let match = s.match(voteRegex);
|
|
130
|
-
if (!match)
|
|
131
|
-
throw new Error("Invalid quotation format: " + s);
|
|
132
|
-
let m = {};
|
|
133
|
-
m = {
|
|
134
|
-
originalAuthor: match[1], authorVerification: match[2], originalTime: match[3], source: match[4],
|
|
135
|
-
picture: match[5], confidence: match[6], quotation: match[7], paraphrasedStatement: match[8] || match[10],
|
|
136
|
-
type: match[9] ? match[9].toLowerCase().replace(' ', '_') : undefined
|
|
137
|
-
};
|
|
138
|
-
return {
|
|
139
|
-
originalAuthor: m['originalAuthor'],
|
|
140
|
-
authorVerification: m['authorVerification'],
|
|
141
|
-
originalTime: m['originalTime'],
|
|
142
|
-
source: m['source'],
|
|
143
|
-
picture: m['picture'],
|
|
144
|
-
confidence: m['confidence'],
|
|
145
|
-
quotation: m['quotation'],
|
|
146
|
-
paraphrasedStatement: (m['paraphrasedStatement']?.replace(/\n\t\t/g, "\n\t")),
|
|
147
|
-
type: m['type']?.toLowerCase().replace(' ', '_'),
|
|
148
|
-
};
|
|
149
|
-
};
|
|
150
|
-
exports.parseQuotation = parseQuotation;
|
|
151
|
-
const buildPollContent = ({ country, city, legalEntity, domainScope, judges, deadline, poll, scopeDescription, scopeQueryLink, options, allowArbitraryVote, requiredProperty: propertyScope, requiredPropertyObserver: propertyScopeObserver }) => {
|
|
235
|
+
const buildPollContent = ({ deadline, poll, scopeDescription, options, allowArbitraryVote, }) => {
|
|
152
236
|
if (!poll)
|
|
153
|
-
throw
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
(
|
|
168
|
-
|
|
169
|
-
(options.length >
|
|
170
|
-
(options.length >
|
|
171
|
-
(options.length >
|
|
172
|
-
(
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
(
|
|
176
|
-
"";
|
|
237
|
+
throw new Error('Poll must contain a poll question.');
|
|
238
|
+
if (poll.includes('\n'))
|
|
239
|
+
throw new Error('Poll question must be single line.');
|
|
240
|
+
if (scopeDescription && scopeDescription.includes('\n'))
|
|
241
|
+
throw new Error('Scope description must be single line.');
|
|
242
|
+
options.forEach((option, index) => {
|
|
243
|
+
if (option && option.includes('\n'))
|
|
244
|
+
throw new Error(`Option ${index + 1} must be single line.`);
|
|
245
|
+
});
|
|
246
|
+
const content = ' Type: Poll\n' +
|
|
247
|
+
(deadline ? ' Voting deadline: ' + deadline.toUTCString() + '\n' : '') +
|
|
248
|
+
' Poll: ' +
|
|
249
|
+
poll +
|
|
250
|
+
'\n' +
|
|
251
|
+
(options.length > 0 && options[0] ? ' Option 1: ' + options[0] + '\n' : '') +
|
|
252
|
+
(options.length > 1 && options[1] ? ' Option 2: ' + options[1] + '\n' : '') +
|
|
253
|
+
(options.length > 2 && options[2] ? ' Option 3: ' + options[2] + '\n' : '') +
|
|
254
|
+
(options.length > 3 && options[3] ? ' Option 4: ' + options[3] + '\n' : '') +
|
|
255
|
+
(options.length > 4 && options[4] ? ' Option 5: ' + options[4] + '\n' : '') +
|
|
256
|
+
(allowArbitraryVote === true || allowArbitraryVote === false
|
|
257
|
+
? ' Allow free text votes: ' + (allowArbitraryVote ? 'Yes' : 'No') + '\n'
|
|
258
|
+
: '') +
|
|
259
|
+
(scopeDescription ? ' Who can vote: ' + scopeDescription + '\n' : '');
|
|
177
260
|
return content;
|
|
178
261
|
};
|
|
179
262
|
exports.buildPollContent = buildPollContent;
|
|
180
|
-
const parsePoll = (
|
|
181
|
-
if (version
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
+
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
judges: m[1], deadline: m[2], poll: m[3],
|
|
203
|
-
option1: m[4], option2: m[5], option3: m[6], option4: m[7], option5: m[8],
|
|
204
|
-
allowArbitraryVote: m[9],
|
|
205
|
-
whoCanVote: m[10]
|
|
206
|
-
};
|
|
207
|
-
const whoCanVoteParsed = {};
|
|
208
|
-
if (m.whoCanVote) {
|
|
209
|
-
const whoCanVoteRegex = new RegExp(''
|
|
210
|
-
+ /^\n\t\tDescription: (?<scopeDescription>[^\n]+?)\n/.source
|
|
211
|
-
+ /(?:\t\tCountry scope: (?<countryScope>[^\n]+?)\n)?/.source
|
|
212
|
-
+ /(?:\t\tCity scope: (?<cityScope>[^\n]+?)\n)?/.source
|
|
213
|
-
+ /(?:\t\tLegal form scope: (?<legalEntity>[^\n]+?)\n)?/.source
|
|
214
|
-
+ /(?:\t\tDomain scope: (?<domainScope>[^\n]+?)\n)?/.source
|
|
215
|
-
+ /(?:\t\tAll entities with the following property: (?<propertyScope>[^\n]+?)\n)?/.source
|
|
216
|
-
+ /(?:\t\tAs observed by: (?<propertyScopeObserver>[^\n]+?)\n)?/.source
|
|
217
|
-
+ /(?:\t\tLink to query defining who can vote: (?<scopeQueryLink>[^\n]+?)\n)?/.source
|
|
218
|
-
+ /$/.source);
|
|
219
|
-
let m2 = m.whoCanVote.match(whoCanVoteRegex);
|
|
220
|
-
if (!m2)
|
|
221
|
-
throw new Error("Invalid who can vote section: " + m.whoCanVote);
|
|
222
|
-
whoCanVoteParsed['scopeDescription'] = m2[1];
|
|
223
|
-
whoCanVoteParsed['country'] = m2[2];
|
|
224
|
-
whoCanVoteParsed['city'] = m2[3];
|
|
225
|
-
whoCanVoteParsed['legalEntity'] = m2[4];
|
|
226
|
-
whoCanVoteParsed['domainScopeStr'] = m2[5];
|
|
227
|
-
whoCanVoteParsed['requiredProperty'] = m2[6];
|
|
228
|
-
whoCanVoteParsed['requiredPropertyObserver'] = m2[7];
|
|
229
|
-
whoCanVoteParsed['scopeQueryLink'] = m2[8];
|
|
230
|
-
}
|
|
231
|
-
const options = [m.option1, m.option2, m.option3, m.option4, m.option5].filter(o => o);
|
|
232
|
-
const domainScope = whoCanVoteParsed.domainScopeStr?.split(', ');
|
|
233
|
-
const allowArbitraryVote = (m['allowArbitraryVote'] === 'Yes' ? true :
|
|
234
|
-
(m['allowArbitraryVote'] === 'No' ? false : undefined));
|
|
235
|
-
const deadlineStr = m.deadline;
|
|
263
|
+
const parsePoll = (content, version) => {
|
|
264
|
+
if (version !== '5')
|
|
265
|
+
throw new Error('Invalid version ' + version);
|
|
266
|
+
const pollRegex = new RegExp('' +
|
|
267
|
+
/^ Type: Poll\n/.source +
|
|
268
|
+
/(?: Voting deadline: (?<deadline>[^\n]+?)\n)?/.source +
|
|
269
|
+
/ Poll: (?<poll>[^\n]+?)\n/.source +
|
|
270
|
+
/(?: Option 1: (?<option1>[^\n]+?)\n)?/.source +
|
|
271
|
+
/(?: Option 2: (?<option2>[^\n]+?)\n)?/.source +
|
|
272
|
+
/(?: Option 3: (?<option3>[^\n]+?)\n)?/.source +
|
|
273
|
+
/(?: Option 4: (?<option4>[^\n]+?)\n)?/.source +
|
|
274
|
+
/(?: Option 5: (?<option5>[^\n]+?)\n)?/.source +
|
|
275
|
+
/(?: Allow free text votes: (?<allowArbitraryVote>Yes|No)\n)?/.source +
|
|
276
|
+
/(?: Who can vote: (?<scopeDescription>[^\n]+?)\n)?/.source +
|
|
277
|
+
/$/.source);
|
|
278
|
+
const match = content.match(pollRegex);
|
|
279
|
+
if (!match || !match.groups)
|
|
280
|
+
throw new Error('Invalid poll format: ' + content);
|
|
281
|
+
const { deadline, poll, option1, option2, option3, option4, option5, allowArbitraryVote: allowArbitraryVoteStr, scopeDescription, } = match.groups;
|
|
282
|
+
const options = [option1, option2, option3, option4, option5].filter((o) => o);
|
|
283
|
+
const allowArbitraryVote = allowArbitraryVoteStr === 'Yes' ? true : allowArbitraryVoteStr === 'No' ? false : undefined;
|
|
284
|
+
const deadlineStr = deadline;
|
|
236
285
|
if (deadlineStr && !deadlineStr.match(constants_1.UTCFormat))
|
|
237
|
-
throw new Error(
|
|
286
|
+
throw new Error('Invalid poll, deadline must be in UTC: ' + deadlineStr);
|
|
238
287
|
return {
|
|
239
|
-
judges: m['judges'],
|
|
240
288
|
deadline: deadlineStr ? new Date(deadlineStr) : undefined,
|
|
241
|
-
poll
|
|
289
|
+
poll,
|
|
242
290
|
options,
|
|
243
291
|
allowArbitraryVote,
|
|
244
|
-
|
|
245
|
-
scopeDescription: whoCanVoteParsed['scopeDescription'],
|
|
246
|
-
requiredProperty: whoCanVoteParsed['requiredProperty'],
|
|
247
|
-
requiredPropertyObserver: whoCanVoteParsed['requiredPropertyObserver'],
|
|
248
|
-
scopeQueryLink: whoCanVoteParsed['scopeQueryLink'],
|
|
249
|
-
city: whoCanVoteParsed['city'],
|
|
250
|
-
legalEntity: whoCanVoteParsed['legalEntity'],
|
|
251
|
-
domainScope: (domainScope && domainScope.length > 0) ? domainScope : undefined,
|
|
292
|
+
scopeDescription,
|
|
252
293
|
};
|
|
253
294
|
};
|
|
254
295
|
exports.parsePoll = parsePoll;
|
|
255
|
-
const buildOrganisationVerificationContent = ({ name, englishName, country, city, province, legalForm, department, domain, foreignDomain, serialNumber, confidence, reliabilityPolicy, employeeCount, pictureHash, latitude, longitude, population }) => {
|
|
296
|
+
const buildOrganisationVerificationContent = ({ name, englishName, country, city, province, legalForm, department, domain, foreignDomain, serialNumber, confidence, reliabilityPolicy, employeeCount, pictureHash, latitude, longitude, population, publicKey, }) => {
|
|
256
297
|
if (!name || !country || !legalForm || (!domain && !foreignDomain))
|
|
257
|
-
throw new Error(
|
|
298
|
+
throw new Error('Missing required fields');
|
|
258
299
|
if (!Object.values(constants_1.legalForms).includes(legalForm))
|
|
259
|
-
throw new Error(
|
|
300
|
+
throw new Error('Invalid legal form ' + legalForm);
|
|
260
301
|
if (employeeCount && !Object.values(constants_1.peopleCountBuckets).includes(employeeCount))
|
|
261
|
-
throw new Error(
|
|
302
|
+
throw new Error('Invalid employee count ' + employeeCount);
|
|
262
303
|
if (population && !Object.values(constants_1.peopleCountBuckets).includes(population))
|
|
263
|
-
throw new Error(
|
|
304
|
+
throw new Error('Invalid population ' + population);
|
|
264
305
|
if (confidence && !('' + confidence)?.match(/^[0-9.]+$/))
|
|
265
|
-
throw new Error(
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
(
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
(
|
|
285
|
-
(
|
|
286
|
-
|
|
306
|
+
throw new Error('Invalid confidence ' + confidence);
|
|
307
|
+
if (pictureHash && !pictureHash.match(/^[A-Za-z0-9_-]+\.[a-zA-Z0-9]+$/)) {
|
|
308
|
+
throw new Error("Logo must be in format 'base64hash.extension' (URL-safe base64)");
|
|
309
|
+
}
|
|
310
|
+
if (publicKey && !publicKey.match(/^[A-Za-z0-9_-]+$/)) {
|
|
311
|
+
throw new Error('Public key must be in URL-safe base64 format (A-Z, a-z, 0-9, _, -)');
|
|
312
|
+
}
|
|
313
|
+
return (' Type: Organisation verification\n' +
|
|
314
|
+
' Description: We verified the following information about an organisation.\n' +
|
|
315
|
+
' Name: ' +
|
|
316
|
+
name +
|
|
317
|
+
'\n' +
|
|
318
|
+
(englishName ? ' English name: ' + englishName + '\n' : '') +
|
|
319
|
+
' Country: ' +
|
|
320
|
+
country +
|
|
321
|
+
'\n' +
|
|
322
|
+
' Legal form: ' +
|
|
323
|
+
legalForm +
|
|
324
|
+
'\n' +
|
|
325
|
+
(domain ? ' Owner of the domain: ' + domain + '\n' : '') +
|
|
326
|
+
(foreignDomain
|
|
327
|
+
? ' Foreign domain used for publishing statements: ' + foreignDomain + '\n'
|
|
328
|
+
: '') +
|
|
329
|
+
(department ? ' Department using the domain: ' + department + '\n' : '') +
|
|
330
|
+
(province ? ' Province or state: ' + province + '\n' : '') +
|
|
331
|
+
(serialNumber ? ' Business register number: ' + serialNumber + '\n' : '') +
|
|
332
|
+
(city ? ' City: ' + city + '\n' : '') +
|
|
333
|
+
(latitude ? ' Latitude: ' + latitude + '\n' : '') +
|
|
334
|
+
(longitude ? ' Longitude: ' + longitude + '\n' : '') +
|
|
335
|
+
(population ? ' Population: ' + population + '\n' : '') +
|
|
336
|
+
(pictureHash ? ' Logo: ' + pictureHash + '\n' : '') +
|
|
337
|
+
(employeeCount ? ' Employee count: ' + employeeCount + '\n' : '') +
|
|
338
|
+
(publicKey ? ' Public key: ' + publicKey + '\n' : '') +
|
|
339
|
+
(reliabilityPolicy ? ' Reliability policy: ' + reliabilityPolicy + '\n' : '') +
|
|
340
|
+
(confidence ? ' Confidence: ' + confidence + '\n' : ''));
|
|
287
341
|
};
|
|
288
342
|
exports.buildOrganisationVerificationContent = buildOrganisationVerificationContent;
|
|
289
|
-
const parseOrganisationVerification = (
|
|
290
|
-
const organisationVerificationRegex = new RegExp(''
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
343
|
+
const parseOrganisationVerification = (content) => {
|
|
344
|
+
const organisationVerificationRegex = new RegExp('' +
|
|
345
|
+
/^ Type: Organisation verification\n/.source +
|
|
346
|
+
/ Description: We verified the following information about an organisation.\n/.source +
|
|
347
|
+
/ Name: (?<name>[^\n]+?)\n/.source +
|
|
348
|
+
/(?: English name: (?<englishName>[^\n]+?)\n)?/.source +
|
|
349
|
+
/ Country: (?<country>[^\n]+?)\n/.source +
|
|
350
|
+
/ Legal (?:form|entity): (?<legalForm>[^\n]+?)\n/.source +
|
|
351
|
+
/(?: Owner of the domain: (?<domain>[^\n]+?)\n)?/.source +
|
|
352
|
+
/(?: Foreign domain used for publishing statements: (?<foreignDomain>[^\n]+?)\n)?/.source +
|
|
353
|
+
/(?: Department using the domain: (?<department>[^\n]+?)\n)?/.source +
|
|
354
|
+
/(?: Province or state: (?<province>[^\n]+?)\n)?/.source +
|
|
355
|
+
/(?: Business register number: (?<serialNumber>[^\n]+?)\n)?/.source +
|
|
356
|
+
/(?: City: (?<city>[^\n]+?)\n)?/.source +
|
|
357
|
+
/(?: Latitude: (?<latitude>[^\n]+?)\n)?/.source +
|
|
358
|
+
/(?: Longitude: (?<longitude>[^\n]+?)\n)?/.source +
|
|
359
|
+
/(?: Population: (?<population>[^\n]+?)\n)?/.source +
|
|
360
|
+
/(?: Logo: (?<pictureHash>[A-Za-z0-9_-]+\.[a-zA-Z0-9]+)\n)?/.source +
|
|
361
|
+
/(?: Employee count: (?<employeeCount>[01,+-]+?)\n)?/.source +
|
|
362
|
+
/(?: Public key: (?<publicKey>[A-Za-z0-9_-]+)\n)?/.source +
|
|
363
|
+
/(?: Reliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source +
|
|
364
|
+
/(?: Confidence: (?<confidence>[0-9.]+?))?/.source +
|
|
365
|
+
/\n?$/.source);
|
|
366
|
+
const match = content.match(organisationVerificationRegex);
|
|
367
|
+
if (!match || !match.groups)
|
|
368
|
+
throw new Error('Invalid organisation verification format: ' + content);
|
|
369
|
+
const { name, englishName, country, legalForm, domain, foreignDomain, department, province, serialNumber, city, latitude, longitude, population, pictureHash, employeeCount, publicKey, reliabilityPolicy, confidence, } = match.groups;
|
|
370
|
+
if (!(0, types_1.isLegalForm)(legalForm)) {
|
|
371
|
+
throw new Error('Invalid legal form after validation: ' + legalForm);
|
|
372
|
+
}
|
|
314
373
|
return {
|
|
315
|
-
name
|
|
316
|
-
englishName
|
|
317
|
-
country
|
|
318
|
-
legalForm
|
|
319
|
-
domain
|
|
320
|
-
foreignDomain
|
|
321
|
-
department
|
|
322
|
-
province
|
|
323
|
-
serialNumber
|
|
324
|
-
city
|
|
325
|
-
latitude:
|
|
326
|
-
longitude:
|
|
327
|
-
population:
|
|
328
|
-
pictureHash
|
|
329
|
-
employeeCount:
|
|
330
|
-
|
|
331
|
-
|
|
374
|
+
name,
|
|
375
|
+
englishName,
|
|
376
|
+
country,
|
|
377
|
+
legalForm,
|
|
378
|
+
domain,
|
|
379
|
+
foreignDomain,
|
|
380
|
+
department,
|
|
381
|
+
province,
|
|
382
|
+
serialNumber,
|
|
383
|
+
city,
|
|
384
|
+
latitude: latitude ? parseFloat(latitude) : undefined,
|
|
385
|
+
longitude: longitude ? parseFloat(longitude) : undefined,
|
|
386
|
+
population: population && (0, types_1.isPeopleCountBucket)(population) ? population : undefined,
|
|
387
|
+
pictureHash,
|
|
388
|
+
employeeCount: employeeCount && (0, types_1.isPeopleCountBucket)(employeeCount) ? employeeCount : undefined,
|
|
389
|
+
publicKey,
|
|
390
|
+
reliabilityPolicy,
|
|
391
|
+
confidence: confidence ? parseFloat(confidence) : undefined,
|
|
332
392
|
};
|
|
333
393
|
};
|
|
334
394
|
exports.parseOrganisationVerification = parseOrganisationVerification;
|
|
335
|
-
const buildPersonVerificationContent = ({ name, countryOfBirth, cityOfBirth, ownDomain, foreignDomain, dateOfBirth, jobTitle, employer, verificationMethod, confidence, picture, reliabilityPolicy }) => {
|
|
395
|
+
const buildPersonVerificationContent = ({ name, countryOfBirth, cityOfBirth, ownDomain, foreignDomain, dateOfBirth, jobTitle, employer, verificationMethod, confidence, picture, reliabilityPolicy, publicKey, }) => {
|
|
336
396
|
if (!name || !countryOfBirth || !cityOfBirth || !dateOfBirth || (!ownDomain && !foreignDomain)) {
|
|
337
|
-
|
|
338
|
-
|
|
397
|
+
throw new Error('Missing required fields for person verification');
|
|
398
|
+
}
|
|
399
|
+
if (publicKey && !publicKey.match(/^[A-Za-z0-9_-]+$/)) {
|
|
400
|
+
throw new Error('Public key must be in URL-safe base64 format (A-Z, a-z, 0-9, _, -)');
|
|
339
401
|
}
|
|
340
|
-
const [day, month, year] = dateOfBirth
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
(
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
402
|
+
const [day, month, year] = dateOfBirth
|
|
403
|
+
.toUTCString()
|
|
404
|
+
.split(' ')
|
|
405
|
+
.filter((_i, j) => [1, 2, 3].includes(j));
|
|
406
|
+
const content = ' Type: Person verification\n' +
|
|
407
|
+
' Description: We verified the following information about a person.\n' +
|
|
408
|
+
' Name: ' +
|
|
409
|
+
name +
|
|
410
|
+
'\n' +
|
|
411
|
+
' Date of birth: ' +
|
|
412
|
+
[day.replace(/^0/, ''), month, year].join(' ') +
|
|
413
|
+
'\n' +
|
|
414
|
+
' City of birth: ' +
|
|
415
|
+
cityOfBirth +
|
|
416
|
+
'\n' +
|
|
417
|
+
' Country of birth: ' +
|
|
418
|
+
countryOfBirth +
|
|
419
|
+
'\n' +
|
|
420
|
+
(jobTitle ? ' Job title: ' + jobTitle + '\n' : '') +
|
|
421
|
+
(employer ? ' Employer: ' + employer + '\n' : '') +
|
|
422
|
+
(ownDomain ? ' Owner of the domain: ' + ownDomain + '\n' : '') +
|
|
423
|
+
(foreignDomain
|
|
424
|
+
? ' Foreign domain used for publishing statements: ' + foreignDomain + '\n'
|
|
425
|
+
: '') +
|
|
426
|
+
(picture ? ' Picture: ' + picture + '\n' : '') +
|
|
427
|
+
(verificationMethod ? ' Verification method: ' + verificationMethod + '\n' : '') +
|
|
428
|
+
(publicKey ? ' Public key: ' + publicKey + '\n' : '') +
|
|
429
|
+
(confidence ? ' Confidence: ' + confidence + '\n' : '') +
|
|
430
|
+
(reliabilityPolicy ? ' Reliability policy: ' + reliabilityPolicy + '\n' : '');
|
|
357
431
|
return content;
|
|
358
432
|
};
|
|
359
433
|
exports.buildPersonVerificationContent = buildPersonVerificationContent;
|
|
360
|
-
const parsePersonVerification = (
|
|
361
|
-
const domainVerificationRegex = new RegExp(''
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
434
|
+
const parsePersonVerification = (content) => {
|
|
435
|
+
const domainVerificationRegex = new RegExp('' +
|
|
436
|
+
/^ Type: Person verification\n/.source +
|
|
437
|
+
/ Description: We verified the following information about a person.\n/.source +
|
|
438
|
+
/ Name: (?<name>[^\n]+?)\n/.source +
|
|
439
|
+
/ Date of birth: (?<dateOfBirth>[^\n]+?)\n/.source +
|
|
440
|
+
/ City of birth: (?<cityOfBirth>[^\n]+?)\n/.source +
|
|
441
|
+
/ Country of birth: (?<countryOfBirth>[^\n]+?)\n/.source +
|
|
442
|
+
/(?: Job title: (?<jobTitle>[^\n]+?)\n)?/.source +
|
|
443
|
+
/(?: Employer: (?<employer>[^\n]+?)\n)?/.source +
|
|
444
|
+
/(?: Owner of the domain: (?<domain>[^\n]+?)\n)?/.source +
|
|
445
|
+
/(?: Foreign domain used for publishing statements: (?<foreignDomain>[^\n]+?)\n)?/.source +
|
|
446
|
+
/(?: Picture: (?<picture>[^\n]+?)\n)?/.source +
|
|
447
|
+
/(?: Verification method: (?<verificationMethod>[^\n]+?)\n)?/.source +
|
|
448
|
+
/(?: Public key: (?<publicKey>[A-Za-z0-9_-]+)\n)?/.source +
|
|
449
|
+
/(?: Confidence: (?<confidence>[^\n]+?)\n)?/.source +
|
|
450
|
+
/(?: Reliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source +
|
|
451
|
+
/$/.source);
|
|
452
|
+
const match = content.match(domainVerificationRegex);
|
|
453
|
+
if (!match || !match.groups)
|
|
454
|
+
throw new Error('Invalid person verification format: ' + content);
|
|
455
|
+
const { name, dateOfBirth: dateOfBirthStr, cityOfBirth, countryOfBirth, jobTitle, employer, domain, foreignDomain, picture, verificationMethod, publicKey, confidence, reliabilityPolicy, } = match.groups;
|
|
456
|
+
if (dateOfBirthStr && !dateOfBirthStr.match(utils_1.birthDateFormat))
|
|
457
|
+
throw new Error('Invalid birth date format: ' + dateOfBirthStr);
|
|
458
|
+
const { d, month, y } = dateOfBirthStr.match(utils_1.birthDateFormat)?.groups || {};
|
|
383
459
|
if (!d || !month || !y)
|
|
384
|
-
throw new Error(
|
|
460
|
+
throw new Error('Invalid birth date format: ' + dateOfBirthStr);
|
|
385
461
|
return {
|
|
386
|
-
name
|
|
462
|
+
name,
|
|
387
463
|
dateOfBirth: new Date(Date.UTC(parseInt(y), (0, utils_1.monthIndex)(month), parseInt(d))),
|
|
388
|
-
cityOfBirth
|
|
389
|
-
countryOfBirth
|
|
390
|
-
jobTitle
|
|
391
|
-
employer
|
|
392
|
-
ownDomain:
|
|
393
|
-
foreignDomain
|
|
394
|
-
picture
|
|
395
|
-
verificationMethod
|
|
396
|
-
|
|
397
|
-
|
|
464
|
+
cityOfBirth,
|
|
465
|
+
countryOfBirth,
|
|
466
|
+
jobTitle,
|
|
467
|
+
employer,
|
|
468
|
+
ownDomain: domain,
|
|
469
|
+
foreignDomain,
|
|
470
|
+
picture,
|
|
471
|
+
verificationMethod,
|
|
472
|
+
publicKey,
|
|
473
|
+
confidence: confidence ? parseFloat(confidence) : undefined,
|
|
474
|
+
reliabilityPolicy,
|
|
398
475
|
};
|
|
399
476
|
};
|
|
400
477
|
exports.parsePersonVerification = parsePersonVerification;
|
|
401
478
|
const buildVoteContent = ({ pollHash, poll, vote }) => {
|
|
402
|
-
const content =
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
479
|
+
const content = ' Type: Vote\n' +
|
|
480
|
+
' Poll id: ' +
|
|
481
|
+
pollHash +
|
|
482
|
+
'\n' +
|
|
483
|
+
' Poll:\n ' +
|
|
484
|
+
poll +
|
|
485
|
+
'\n' +
|
|
486
|
+
' Option:\n ' +
|
|
487
|
+
vote +
|
|
488
|
+
'\n';
|
|
408
489
|
return content;
|
|
409
490
|
};
|
|
410
491
|
exports.buildVoteContent = buildVoteContent;
|
|
411
|
-
const parseVote = (
|
|
412
|
-
const voteRegex = new RegExp(''
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
const
|
|
419
|
-
if (!
|
|
420
|
-
throw new Error(
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
poll: m[2],
|
|
424
|
-
vote: m[3]
|
|
425
|
-
};
|
|
492
|
+
const parseVote = (content) => {
|
|
493
|
+
const voteRegex = new RegExp('' +
|
|
494
|
+
/^ Type: Vote\n/.source +
|
|
495
|
+
/ Poll id: (?<pollHash>[^\n]+?)\n/.source +
|
|
496
|
+
/ Poll:\n (?<poll>[^\n]+?)\n/.source +
|
|
497
|
+
/ Option:\n (?<vote>[^\n]+?)\n/.source +
|
|
498
|
+
/$/.source);
|
|
499
|
+
const match = content.match(voteRegex);
|
|
500
|
+
if (!match || !match.groups)
|
|
501
|
+
throw new Error('Invalid vote format: ' + content);
|
|
502
|
+
const { pollHash, poll, vote } = match.groups;
|
|
503
|
+
return { pollHash, poll, vote };
|
|
426
504
|
};
|
|
427
505
|
exports.parseVote = parseVote;
|
|
428
|
-
const buildDisputeAuthenticityContent = ({ hash, confidence, reliabilityPolicy }) => {
|
|
429
|
-
const content =
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
(
|
|
435
|
-
|
|
506
|
+
const buildDisputeAuthenticityContent = ({ hash, confidence, reliabilityPolicy, }) => {
|
|
507
|
+
const content = ' Type: Dispute statement authenticity\n' +
|
|
508
|
+
' Description: We think that the referenced statement is not authentic.\n' +
|
|
509
|
+
' Hash of referenced statement: ' +
|
|
510
|
+
hash +
|
|
511
|
+
'\n' +
|
|
512
|
+
(confidence ? ' Confidence: ' + confidence + '\n' : '') +
|
|
513
|
+
(reliabilityPolicy ? ' Reliability policy: ' + reliabilityPolicy + '\n' : '');
|
|
436
514
|
return content;
|
|
437
515
|
};
|
|
438
516
|
exports.buildDisputeAuthenticityContent = buildDisputeAuthenticityContent;
|
|
439
|
-
const parseDisputeAuthenticity = (
|
|
440
|
-
const disputeRegex = new RegExp(''
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
const
|
|
448
|
-
if (!
|
|
449
|
-
throw new Error(
|
|
517
|
+
const parseDisputeAuthenticity = (content) => {
|
|
518
|
+
const disputeRegex = new RegExp('' +
|
|
519
|
+
/^ Type: Dispute statement authenticity\n/.source +
|
|
520
|
+
/ Description: We think that the referenced statement is not authentic.\n/.source +
|
|
521
|
+
/ Hash of referenced statement: (?<hash>[^\n]+?)\n/.source +
|
|
522
|
+
/(?: Confidence: (?<confidence>[^\n]*?)\n)?/.source +
|
|
523
|
+
/(?: Reliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source +
|
|
524
|
+
/$/.source);
|
|
525
|
+
const match = content.match(disputeRegex);
|
|
526
|
+
if (!match || !match.groups)
|
|
527
|
+
throw new Error('Invalid dispute authenticity format: ' + content);
|
|
528
|
+
const { hash, confidence, reliabilityPolicy } = match.groups;
|
|
450
529
|
return {
|
|
451
|
-
hash
|
|
452
|
-
confidence:
|
|
453
|
-
reliabilityPolicy
|
|
530
|
+
hash,
|
|
531
|
+
confidence: confidence ? parseFloat(confidence) : undefined,
|
|
532
|
+
reliabilityPolicy,
|
|
454
533
|
};
|
|
455
534
|
};
|
|
456
535
|
exports.parseDisputeAuthenticity = parseDisputeAuthenticity;
|
|
457
|
-
const buildDisputeContentContent = ({ hash, confidence, reliabilityPolicy }) => {
|
|
458
|
-
const content =
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
(
|
|
464
|
-
|
|
536
|
+
const buildDisputeContentContent = ({ hash, confidence, reliabilityPolicy, }) => {
|
|
537
|
+
const content = ' Type: Dispute statement content\n' +
|
|
538
|
+
' Description: We think that the content of the referenced statement is false.\n' +
|
|
539
|
+
' Hash of referenced statement: ' +
|
|
540
|
+
hash +
|
|
541
|
+
'\n' +
|
|
542
|
+
(confidence ? ' Confidence: ' + confidence + '\n' : '') +
|
|
543
|
+
(reliabilityPolicy ? ' Reliability policy: ' + reliabilityPolicy + '\n' : '');
|
|
465
544
|
return content;
|
|
466
545
|
};
|
|
467
546
|
exports.buildDisputeContentContent = buildDisputeContentContent;
|
|
468
|
-
const parseDisputeContent = (
|
|
469
|
-
const disputeRegex = new RegExp(''
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
const
|
|
477
|
-
if (!
|
|
478
|
-
throw new Error(
|
|
547
|
+
const parseDisputeContent = (content) => {
|
|
548
|
+
const disputeRegex = new RegExp('' +
|
|
549
|
+
/^ Type: Dispute statement content\n/.source +
|
|
550
|
+
/ Description: We think that the content of the referenced statement is false.\n/.source +
|
|
551
|
+
/ Hash of referenced statement: (?<hash>[^\n]+?)\n/.source +
|
|
552
|
+
/(?: Confidence: (?<confidence>[^\n]*?)\n)?/.source +
|
|
553
|
+
/(?: Reliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source +
|
|
554
|
+
/$/.source);
|
|
555
|
+
const match = content.match(disputeRegex);
|
|
556
|
+
if (!match || !match.groups)
|
|
557
|
+
throw new Error('Invalid dispute content format: ' + content);
|
|
558
|
+
const { hash, confidence, reliabilityPolicy } = match.groups;
|
|
479
559
|
return {
|
|
480
|
-
hash
|
|
481
|
-
confidence:
|
|
482
|
-
reliabilityPolicy
|
|
560
|
+
hash,
|
|
561
|
+
confidence: confidence ? parseFloat(confidence) : undefined,
|
|
562
|
+
reliabilityPolicy,
|
|
483
563
|
};
|
|
484
564
|
};
|
|
485
565
|
exports.parseDisputeContent = parseDisputeContent;
|
|
486
566
|
const buildResponseContent = ({ hash, response }) => {
|
|
487
|
-
const content =
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
567
|
+
const content = ' Type: Response\n' +
|
|
568
|
+
' Hash of referenced statement: ' +
|
|
569
|
+
hash +
|
|
570
|
+
'\n' +
|
|
571
|
+
' Response:\n ' +
|
|
572
|
+
response +
|
|
573
|
+
'\n';
|
|
492
574
|
return content;
|
|
493
575
|
};
|
|
494
576
|
exports.buildResponseContent = buildResponseContent;
|
|
495
|
-
const parseResponseContent = (
|
|
496
|
-
const
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
const
|
|
502
|
-
if (!
|
|
503
|
-
throw new Error(
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
response: m[2]
|
|
507
|
-
};
|
|
577
|
+
const parseResponseContent = (content) => {
|
|
578
|
+
const responseRegex = new RegExp('' +
|
|
579
|
+
/^ Type: Response\n/.source +
|
|
580
|
+
/ Hash of referenced statement: (?<hash>[^\n]+?)\n/.source +
|
|
581
|
+
/ Response:\n (?<response>[^\n]*?)\n/.source +
|
|
582
|
+
/$/.source);
|
|
583
|
+
const match = content.match(responseRegex);
|
|
584
|
+
if (!match || !match.groups)
|
|
585
|
+
throw new Error('Invalid response content format: ' + content);
|
|
586
|
+
const { hash, response } = match.groups;
|
|
587
|
+
return { hash, response };
|
|
508
588
|
};
|
|
509
589
|
exports.parseResponseContent = parseResponseContent;
|
|
510
590
|
const buildPDFSigningContent = ({ hash }) => {
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
591
|
+
if (!hash.match(/^[A-Za-z0-9_-]+$/)) {
|
|
592
|
+
throw new Error('PDF file hash must be in URL-safe base64 format (A-Z, a-z, 0-9, _, -)');
|
|
593
|
+
}
|
|
594
|
+
const content = ' Type: Sign PDF\n' +
|
|
595
|
+
' Description: We hereby digitally sign the referenced PDF file.\n' +
|
|
596
|
+
' PDF file hash: ' +
|
|
597
|
+
hash +
|
|
598
|
+
'\n';
|
|
516
599
|
return content;
|
|
517
600
|
};
|
|
518
601
|
exports.buildPDFSigningContent = buildPDFSigningContent;
|
|
519
|
-
const parsePDFSigning = (
|
|
520
|
-
const signingRegex = new RegExp(''
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const
|
|
526
|
-
if (!
|
|
527
|
-
throw new Error(
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
};
|
|
602
|
+
const parsePDFSigning = (content) => {
|
|
603
|
+
const signingRegex = new RegExp('' +
|
|
604
|
+
/^ Type: Sign PDF\n/.source +
|
|
605
|
+
/ Description: We hereby digitally sign the referenced PDF file.\n/.source +
|
|
606
|
+
/ PDF file hash: (?<hash>[A-Za-z0-9_-]+)\n/.source +
|
|
607
|
+
/$/.source);
|
|
608
|
+
const match = content.match(signingRegex);
|
|
609
|
+
if (!match || !match.groups)
|
|
610
|
+
throw new Error('Invalid PDF signing format: ' + content);
|
|
611
|
+
const { hash } = match.groups;
|
|
612
|
+
return { hash };
|
|
531
613
|
};
|
|
532
614
|
exports.parsePDFSigning = parsePDFSigning;
|
|
533
|
-
const buildRating = ({ subjectName, subjectType, subjectReference, documentFileHash, rating, quality, comment }) => {
|
|
615
|
+
const buildRating = ({ subjectName, subjectType, subjectReference, documentFileHash, rating, quality, comment, }) => {
|
|
534
616
|
if (![1, 2, 3, 4, 5].includes(rating))
|
|
535
|
-
throw new Error(
|
|
536
|
-
const content =
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
(
|
|
542
|
-
(
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
617
|
+
throw new Error('Invalid rating: ' + rating);
|
|
618
|
+
const content = ' Type: Rating\n' +
|
|
619
|
+
(subjectType ? ' Subject type: ' + subjectType + '\n' : '') +
|
|
620
|
+
' Subject name: ' +
|
|
621
|
+
subjectName +
|
|
622
|
+
'\n' +
|
|
623
|
+
(subjectReference ? ' URL that identifies the subject: ' + subjectReference + '\n' : '') +
|
|
624
|
+
(documentFileHash ? ' Document file hash: ' + documentFileHash + '\n' : '') +
|
|
625
|
+
(quality ? ' Rated quality: ' + quality + '\n' : '') +
|
|
626
|
+
' Our rating: ' +
|
|
627
|
+
rating +
|
|
628
|
+
'/5 Stars\n' +
|
|
629
|
+
(comment ? ' Comment:\n ' + comment + '\n' : '');
|
|
546
630
|
return content;
|
|
547
631
|
};
|
|
548
632
|
exports.buildRating = buildRating;
|
|
549
|
-
const parseRating = (
|
|
550
|
-
const ratingRegex = new RegExp(''
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
if (!
|
|
562
|
-
throw new Error(
|
|
563
|
-
const rating =
|
|
633
|
+
const parseRating = (content) => {
|
|
634
|
+
const ratingRegex = new RegExp('' +
|
|
635
|
+
/^ Type: Rating\n/.source +
|
|
636
|
+
/(?: Subject type: (?<subjectType>[^\n]*?)\n)?/.source +
|
|
637
|
+
/ Subject name: (?<subjectName>[^\n]*?)\n/.source +
|
|
638
|
+
/(?: URL that identifies the subject: (?<subjectReference>[^\n]*?)\n)?/.source +
|
|
639
|
+
/(?: Document file hash: (?<documentFileHash>[^\n]*?)\n)?/.source +
|
|
640
|
+
/(?: Rated quality: (?<quality>[^\n]*?)\n)?/.source +
|
|
641
|
+
/ Our rating: (?<rating>[1-5])\/5 Stars\n/.source +
|
|
642
|
+
/(?: Comment:\n (?<comment>[\s\S]+?)\n)?/.source +
|
|
643
|
+
/$/.source);
|
|
644
|
+
const match = content.match(ratingRegex);
|
|
645
|
+
if (!match || !match.groups)
|
|
646
|
+
throw new Error('Invalid rating format: ' + content);
|
|
647
|
+
const { subjectType, subjectName, subjectReference, documentFileHash, quality, rating: ratingStr, comment, } = match.groups;
|
|
648
|
+
const rating = parseInt(ratingStr);
|
|
564
649
|
if (![1, 2, 3, 4, 5].includes(rating))
|
|
565
|
-
throw new Error(
|
|
566
|
-
if (
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
650
|
+
throw new Error('Invalid rating: ' + ratingStr);
|
|
651
|
+
if (subjectType &&
|
|
652
|
+
![
|
|
653
|
+
'Organisation',
|
|
654
|
+
'Policy proposal',
|
|
655
|
+
'Regulation',
|
|
656
|
+
'Treaty draft',
|
|
657
|
+
'Product',
|
|
658
|
+
'Research publication',
|
|
659
|
+
].includes(subjectType))
|
|
660
|
+
throw new Error('Invalid subject type: ' + subjectType);
|
|
661
|
+
if (!subjectName)
|
|
662
|
+
throw new Error('Missing subject name');
|
|
663
|
+
if (!(0, types_1.isRatingValue)(rating)) {
|
|
664
|
+
throw new Error('Invalid rating after validation: ' + rating);
|
|
665
|
+
}
|
|
571
666
|
return {
|
|
572
|
-
subjectType:
|
|
573
|
-
subjectName
|
|
574
|
-
subjectReference
|
|
575
|
-
documentFileHash
|
|
576
|
-
quality
|
|
667
|
+
subjectType: subjectType,
|
|
668
|
+
subjectName,
|
|
669
|
+
subjectReference,
|
|
670
|
+
documentFileHash,
|
|
671
|
+
quality,
|
|
577
672
|
rating,
|
|
578
|
-
comment
|
|
673
|
+
comment,
|
|
579
674
|
};
|
|
580
675
|
};
|
|
581
676
|
exports.parseRating = parseRating;
|
|
582
|
-
const buildBounty = ({ motivation, bounty, reward, judge, judgePay }) => {
|
|
583
|
-
const content = "\n" +
|
|
584
|
-
"\t" + "Type: Bounty" + "\n" +
|
|
585
|
-
(motivation ? "\t" + "In order to: " + motivation + "\n" : "") +
|
|
586
|
-
"\t" + "We will reward any entity that: " + bounty + "\n" +
|
|
587
|
-
"\t" + "The reward is: " + reward + "\n" +
|
|
588
|
-
"\t" + "In case of dispute, bounty claims are judged by: " + judge + "\n" +
|
|
589
|
-
(judgePay ? "\t" + "The judge will be paid per investigated case with a maxium of: " + judgePay + "\n" : "") +
|
|
590
|
-
"";
|
|
591
|
-
return content;
|
|
592
|
-
};
|
|
593
|
-
exports.buildBounty = buildBounty;
|
|
594
|
-
const parseBounty = (s) => {
|
|
595
|
-
const bountyRegex = new RegExp(''
|
|
596
|
-
+ /^\n\tType: Bounty\n/.source
|
|
597
|
-
+ /(?:\tIn order to: (?<motivation>[^\n]*?)\n)?/.source
|
|
598
|
-
+ /\tWe will reward any entity that: (?<bounty>[^\n]*?)\n/.source
|
|
599
|
-
+ /\tThe reward is: (?<reward>[^\n]*?)\n/.source
|
|
600
|
-
+ /\tIn case of dispute, bounty claims are judged by: (?<judge>[^\n]*?)\n/.source
|
|
601
|
-
+ /(?:\tThe judge will be paid per investigated case with a maxium of: (?<judgePay>[^\n]*?)\n)?/.source
|
|
602
|
-
+ /$/.source);
|
|
603
|
-
const m = s.match(bountyRegex);
|
|
604
|
-
if (!m)
|
|
605
|
-
throw new Error("Invalid bounty format: " + s);
|
|
606
|
-
return {
|
|
607
|
-
motivation: m[1],
|
|
608
|
-
bounty: m[2],
|
|
609
|
-
reward: m[3],
|
|
610
|
-
judge: m[4],
|
|
611
|
-
judgePay: m[5]
|
|
612
|
-
};
|
|
613
|
-
};
|
|
614
|
-
exports.parseBounty = parseBounty;
|
|
615
|
-
const buildObservation = ({ approach, confidence, reliabilityPolicy, subject, subjectReference, observationReference, property, value }) => {
|
|
616
|
-
const content = "\n" +
|
|
617
|
-
"\t" + "Type: Observation" + "\n" +
|
|
618
|
-
(approach ? "\t" + "Approach: " + approach + "\n" : "") +
|
|
619
|
-
(confidence ? "\t" + "Confidence: " + confidence + "\n" : "") +
|
|
620
|
-
(reliabilityPolicy ? "\t" + "Reliability policy: " + reliabilityPolicy + "\n" : "") +
|
|
621
|
-
"\t" + "Subject: " + subject + "\n" +
|
|
622
|
-
(subjectReference ? "\t" + "Subject identity reference: " + subjectReference + "\n" : "") +
|
|
623
|
-
(observationReference ? "\t" + "Observation reference: " + observationReference + "\n" : "") +
|
|
624
|
-
"\t" + "Observed property: " + property + "\n" +
|
|
625
|
-
(value ? "\t" + "Observed value: " + value + "\n" : "") +
|
|
626
|
-
"";
|
|
627
|
-
return content;
|
|
628
|
-
};
|
|
629
|
-
exports.buildObservation = buildObservation;
|
|
630
|
-
const parseObservation = (s) => {
|
|
631
|
-
const observationRegex = new RegExp(''
|
|
632
|
-
+ /^\n\tType: Observation\n/.source
|
|
633
|
-
+ /(?:\tApproach: (?<approach>[^\n]*?)\n)?/.source
|
|
634
|
-
+ /(?:\tConfidence: (?<confidence>[^\n]*?)\n)?/.source
|
|
635
|
-
+ /(?:\tReliability policy: (?<reliabilityPolicy>[^\n]+?)\n)?/.source
|
|
636
|
-
+ /\tSubject: (?<subject>[^\n]*?)\n/.source
|
|
637
|
-
+ /(?:\tSubject identity reference: (?<subjectReference>[^\n]*?)\n)?/.source
|
|
638
|
-
+ /(?:\tObservation reference: (?<observationReference>[^\n]*?)\n)?/.source
|
|
639
|
-
+ /\tObserved property: (?<property>[^\n]*?)\n/.source
|
|
640
|
-
+ /(?:\tObserved value: (?<value>[\s\S]+?)\n)?/.source
|
|
641
|
-
+ /$/.source);
|
|
642
|
-
const m = s.match(observationRegex);
|
|
643
|
-
if (!m)
|
|
644
|
-
throw new Error("Invalid observation format: " + s);
|
|
645
|
-
return {
|
|
646
|
-
approach: m[1],
|
|
647
|
-
confidence: m[2] ? parseFloat(m[2]) : undefined,
|
|
648
|
-
reliabilityPolicy: m[3],
|
|
649
|
-
subject: m[4],
|
|
650
|
-
subjectReference: m[5],
|
|
651
|
-
observationReference: m[6],
|
|
652
|
-
property: m[7],
|
|
653
|
-
value: m[8]
|
|
654
|
-
};
|
|
655
|
-
};
|
|
656
|
-
exports.parseObservation = parseObservation;
|
|
657
|
-
const buildBoycott = ({ description, subject, subjectReference }) => {
|
|
658
|
-
const content = "\n" +
|
|
659
|
-
"\t" + "Type: Boycott" + "\n" +
|
|
660
|
-
(description ? "\t" + "Description: " + description + "\n" : "") +
|
|
661
|
-
"\t" + "Subject: " + subject + "\n" +
|
|
662
|
-
(subjectReference ? "\t" + "Subject identity reference: " + subjectReference + "\n" : "") +
|
|
663
|
-
"";
|
|
664
|
-
return content;
|
|
665
|
-
};
|
|
666
|
-
exports.buildBoycott = buildBoycott;
|
|
667
|
-
const parseBoycott = (s) => {
|
|
668
|
-
const observationRegex = new RegExp(''
|
|
669
|
-
+ /^\n\tType: Boycott\n/.source
|
|
670
|
-
+ /(?:\tDescription: (?<description>[^\n]*?)\n)?/.source
|
|
671
|
-
+ /\tSubject: (?<subject>[^\n]*?)\n/.source
|
|
672
|
-
+ /(?:\tSubject identity reference: (?<subjectReference>[^\n]*?)\n)?/.source
|
|
673
|
-
+ /$/.source);
|
|
674
|
-
const m = s.match(observationRegex);
|
|
675
|
-
if (!m)
|
|
676
|
-
throw new Error("Invalid observation format: " + s);
|
|
677
|
-
return {
|
|
678
|
-
description: m[1],
|
|
679
|
-
subject: m[2],
|
|
680
|
-
subjectReference: m[3],
|
|
681
|
-
};
|
|
682
|
-
};
|
|
683
|
-
exports.parseBoycott = parseBoycott;
|
|
684
677
|
//# sourceMappingURL=protocol.js.map
|