-
Notifications
You must be signed in to change notification settings - Fork 4
/
verifier.ts
89 lines (79 loc) · 2.96 KB
/
verifier.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
export interface Proof {
matcher: string;
variables: {
[name: string]: number;
};
profile: string;
proof: string;
username: string;
service: string;
checks: any[];
}
export interface VerifierProof {
profile: string,
proofUrl: string;
proofJson: string;
service: string;
username: string;
checks: any[];
}
export function getVerifier(proofs: Proof[], proofUrl: string, fingerprint: string) {
for (const proof of proofs) {
const matches = proofUrl.match(new RegExp(proof.matcher));
if (!matches) continue;
const bound = Object.entries(proof.variables).map(([key, value]) => [key, matches[value || 0]]).reduce((previous, current) => { previous[current[0]] = current[1]; return previous;}, { FINGERPRINT: fingerprint } as any);
const profile = proof.profile.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]);
const proofJson = proof.proof.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]);
const username = proof.username.replace(/\{([A-Z]+)\}/g, (_, name) => bound[name]);
return {
profile,
proofUrl,
proofJson,
username,
service: proof.service,
checks: ((proof.checks || []) as any).map((check: any) => ({
relation: check.relation,
proof: check.proof,
claim: check.claim.replace(/\{([A-Z]+)\}/g, (_: any, name: string) => bound[name])
}))
};
}
return null;
}
export async function verify(json: any, checks: any[]) {
for (const check of checks) {
const proofValue = check.proof.reduce((previous: any, current: any) => {
if (current == null || previous == null) return null;
if (Array.isArray(previous) && typeof current === 'string') {
return previous.map(value => value[current]);
}
return previous[current];
}, json);
const claimValue = check.claim;
if (check.relation === 'eq') {
if (proofValue !== claimValue) {
throw new Error(`Proof value ${proofValue} !== claim value ${claimValue}`);
}
} else if (check.relation === 'contains') {
if (!proofValue || proofValue.indexOf(claimValue) === -1) {
throw new Error(`Proof value ${proofValue} does not contain claim value ${claimValue}`);
}
} else if (check.relation === 'oneOf') {
if (!proofValue || proofValue.indexOf(claimValue) === -1) {
throw new Error(`Proof value ${proofValue} does not contain claim value ${claimValue}`);
}
}
}
}
export async function getJson(url: string) {
const response = await fetch(url, {
headers: {
Accept: 'application/json'
},
credentials: 'omit'
});
if (!response.ok) {
throw new Error('Response failed: ' + response.status);
}
return response.json();
}