This repository has been archived by the owner on Oct 21, 2022. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBadge Class.txt
executable file
·80 lines (79 loc) · 8.6 KB
/
Badge Class.txt
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
Type: Badge Class
Version: 2.0
Description: Add a badge class.
Template: {"badgeClass":{"type":"str","desc":"De (ondertekende) badge klasse om op te slaan.","name":"Badge Class"}}
Init: YXdhaXQgcXVlcnkoIkNSRUFURSIsICJiYWRnZWNsYXNzZXMiLCAiKGlkIFZBUkNIQVIoMjU2KSBQUklNQVJZIEtFWSwgIiArDQogICAgImVudGl0eSBWQVJDSEFSKDM1KSBOT1QgTlVMTCBSRUZFUkVOQ0VTIGVudGl0aWVzKGVudGl0eSksIGpzb24gSlNPTiBOT1QgTlVMTCwgZGF0YSBURVhUKTsiLCBbXSk7
Code: bGV0IGJhZGdlQ2xhc3NEYXRhOw0KbGV0IGJhZGdlQ2xhc3NKc29uID0gSlNPTi5wYXJzZShwYXlsb2FkLmJhZGdlQ2xhc3MpOw0KLy9TaWduZWQgYmFkZ2UgY2xhc3MNCmlmIChiYWRnZUNsYXNzSnNvbiA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBiYWRnZUNsYXNzSnNvbi5wYXlsb2FkID09PSAic3RyaW5nIikgew0KICAgIGxldCBiYWRnZUNsYXNzOw0KICAgIGlmIChiYWRnZUNsYXNzSnNvbiA9PT0gdW5kZWZpbmVkKSB7DQogICAgICAgIC8vSWYgaXQgaXMgaW4gY29tcGFjdCBqd3Mgc2VyaWFsaXphdGlvbiBmb3JtYXQgKGJhc2U2NHVybEFsZ29yaXRobS5iYXNlNjR1cmxCYWRnZUNsYXNzLmJhc2U2NHVybFNpZ25hdHVyZSkNCiAgICAgICAgYmFkZ2VDbGFzc0RhdGEgPSBwYXlsb2FkLmJhZGdlQ2xhc3M7DQogICAgICAgIGJhZGdlQ2xhc3MgPSBiYWRnZUNsYXNzRGF0YS5zcGxpdCgiLiIpWzFdOw0KICAgICAgICBpZiAoYmFkZ2VDbGFzcyA9PT0gdW5kZWZpbmVkKSB7DQogICAgICAgICAgICByZXR1cm4gIlNpZ25lZCBiYWRnZSBjbGFzcyBoYXMgaW52YWxpZCBqd3MgY29tcGFjdCBzZXJpYWxpemF0aW9uIGZvcm1hdC4iOw0KICAgICAgICB9DQogICAgfQ0KICAgIGVsc2Ugew0KICAgICAgICAvL0lmIGl0IGlzIGluIGpzb24gc2VyaWFsaXphdGlvbiBmb3JtYXQgKHsicGF5bG9hZCI6ImJhc2U2NHVybEJhZGdlQ2xhc3MiLCAuLi59KQ0KICAgICAgICBiYWRnZUNsYXNzRGF0YSA9IGJhZGdlQ2xhc3NKc29uOw0KICAgICAgICBiYWRnZUNsYXNzID0gYmFkZ2VDbGFzc0pzb24ucGF5bG9hZDsNCiAgICB9DQogICAgLy9qd3MgdXNlcyBiYXNlNjR1cmwgaW5zdGVhZCBvZiBiYXNlNjQgZW5jb2RpbmcsIGNoYW5nZSBpdCBiYWNrLg0KICAgIGJhZGdlQ2xhc3MgPSBiYWRnZUNsYXNzLnJlcGxhY2UoLy0vZywgIisiKS5yZXBsYWNlKC9fL2csICIvIik7DQogICAgd2hpbGUgKChiYWRnZUNsYXNzLmxlbmd0aCAmIDB4MykgIT09IDApIHsNCiAgICAgICAgYmFkZ2VDbGFzcyArPSAiPSI7DQogICAgfQ0KICAgIGlmIChiYWRnZUNsYXNzLnNlYXJjaCgvXltcK1wvLTlBLVphLXpdKj17MCwyfSQvKSAhPT0gMCkgew0KICAgICAgICByZXR1cm4gIlNpZ25lZCBiYWRnZSBjbGFzcyBpcyBub3QgYmFzZTY0dXJsIGVuY29kZWQuIjsNCiAgICB9DQogICAgLy9FeHRyYWN0IHRoZSBqc29uIGJhZGdlIGNsYXNzDQogICAgYmFkZ2VDbGFzc0pzb24gPSBKU09OLnBhcnNlKEJ1ZmZlci5mcm9tKGJhZGdlQ2xhc3MsICJiYXNlNjQiKS50b1N0cmluZygpKTsNCn0NCmlmICh0eXBlb2YgYmFkZ2VDbGFzc0pzb24gIT09ICJvYmplY3QiIHx8IGJhZGdlQ2xhc3NKc29uID09PSBudWxsKSB7DQogICAgcmV0dXJuICJCYWRnZSBjbGFzcyBpcyBpbnZhbGlkIGpzb24uIjsNCn0NCmNvbnN0IGJhZGdlQ2xhc3NJZCA9IGJhZGdlQ2xhc3NKc29uLmlkIHx8IGJhZGdlQ2xhc3NKc29uWyJAaWQiXTsNCmlmICh0eXBlb2YgYmFkZ2VDbGFzc0lkICE9PSAic3RyaW5nIiB8fCBiYWRnZUNsYXNzSWQubGVuZ3RoID09PSAwIHx8IGJhZGdlQ2xhc3NJZC5sZW5ndGggPiAyNTYpIHsNCiAgICByZXR1cm4gIkJhZGdlIGNsYXNzIGlzIG1pc3Npbmcgb3IgaGFzIGludmFsaWQgaWQuIjsNCn0NCi8vTm90IHJlYWxseSBuZWVkZWQgdG8gY2hlY2sgdGhpcyB3aXRoIHNpZ25lZCB2ZXJpZmljYXRpb24sIGJ1dCB3ZSBkbyBub3Qgd2FudCBzb21lb25lIHRvIGNyZWF0ZSBzb21lb25lIGVsc2UncyBiYWRnZWNsYXNzDQpjb25zdCBpc3N1ZXIgPSBiYWRnZUNsYXNzSnNvbi5pc3N1ZXIgfHwgYmFkZ2VDbGFzc0pzb25bIm9iaTppc3N1ZXIiXSB8fCBiYWRnZUNsYXNzSnNvblsiaHR0cHM6Ly93M2lkLm9yZy9vcGVuYmFkZ2VzI2lzc3VlciJdOw0KaWYgKHR5cGVvZiBpc3N1ZXIgIT09ICJzdHJpbmciICYmIHR5cGVvZiBpc3N1ZXIgIT09ICJvYmplY3QiIHx8IGlzc3VlciA9PT0gbnVsbCkgew0KICAgIHJldHVybiAiQmFkZ2UgY2xhc3MgaXMgbWlzc2luZyBvciBoYXMgaW52YWxpZCBpc3N1ZXIuIjsNCn0NCmNvbnN0IGlzc3VlcklkID0gdHlwZW9mIGlzc3VlciA9PT0gInN0cmluZyIgPyBpc3N1ZXIgOiBpc3N1ZXIuaWQgfHwgaXNzdWVyWyJAaWQiXTsNCmlmICh0eXBlb2YgaXNzdWVySWQgIT09ICJzdHJpbmciKSB7DQogICAgcmV0dXJuICJCYWRnZSBjbGFzcyBpcyBtaXNzaW5nIG9yIGhhcyBpbnZhbGlkIGlzc3VlciBpZC4iOw0KfQ0KLy9DaGVjayBpZiB0aGUgZW50aXR5IGV4aXN0cyBhbmQgaXMgbm90IHJldm9rZWQuDQpjb25zdCBlbnRpdHkgPSAoYXdhaXQgcXVlcnkoIlNFTEVDVCIsICJlbnRpdGllcyIsICJXSEVSRSBlbnRpdHkgPSAkMTsiLCBbZnJvbV0pKS5yb3dzWzBdOw0KaWYgKGVudGl0eSA9PT0gdW5kZWZpbmVkKSB7DQogICAgcmV0dXJuICJFbnRpdHkgZG9lcyBub3QgZXhpc3RzIG9yIHVzZXIgaXMgbm90IGFuIGVudGl0eS4iOw0KfQ0KaWYgKGVudGl0eS5yZXZva2VkICE9PSBudWxsKSB7DQogICAgcmV0dXJuICJFbnRpdHkgaXMgd2l0aGRyYXduLiI7DQp9DQovL0NoZWNrIGlmIHRoZSBpbnN0aXR1dGlvbiBpcyBub3Qgd2l0aGRyYXduICh3ZSBhcmUgc3VyZSBpdCBleGlzdHMgaWYgdGhlIGVudGl0eSBleGlzdHMpDQpjb25zdCBpbnN0aXR1dGlvbiA9IChhd2FpdCBxdWVyeSgiU0VMRUNUIiwgImluc3RpdHV0aW9ucyIsICJXSEVSRSBpbnN0aXR1dGlvbiA9ICQxOyIsIFtlbnRpdHkuaW5zdGl0dXRpb25dKSkucm93c1swXTsNCmlmIChpbnN0aXR1dGlvbi5yZXZva2VkICE9PSBudWxsKSB7DQogICAgcmV0dXJuICJJbnN0aXR1dGlvbiBvZiBlbnRpdHkgaXMgd2l0aGRyYXduLiI7DQp9DQplbHNlIGlmIChpbnN0aXR1dGlvbi5pcmkgIT09IGlzc3VlcklkKSB7DQogICAgcmV0dXJuICJJbnN0aXR1dGlvbiBpcyBub3QgdGhlIGlzc3VlciBmb3IgdGhpcyBiYWRnZSBjbGFzcy4iOw0KfQ0KLy9DcmVhdGUgdGhlIGJhZGdlLiBOb3RlIHRoYXQgaXQgbWF5IG5vdCBiZSB2YWxpZCwgYnV0IHRoYXQgaXMgZm9yIHRoZSBjaGVja2VyIHNlcnZpY2UgdG8gcmVzb2x2ZS4NCmNvbnN0IGNyZWF0ZWQgPSBhd2FpdCBxdWVyeSgiSU5TRVJUIiwgImJhZGdlY2xhc3NlcyIsICIoaWQsIGVudGl0eSwganNvbiwgZGF0YSkgVkFMVUVTICgkMSwgJDIsICQzLCAkNCkgIiArDQogICAgIk9OIENPTkZMSUNUIE9OIENPTlNUUkFJTlQgYmFkZ2VjbGFzc2VzX3BrZXkgRE8gVVBEQVRFIFNFVCBqc29uID0gJDMsIGRhdGEgPSAkNCBXSEVSRSBiYWRnZWNsYXNzZXMuZW50aXR5ID0gJDI7IiwgW2JhZGdlQ2xhc3NJZCwgZnJvbSwgSlNPTi5zdHJpbmdpZnkoYmFkZ2VDbGFzc0pzb24pLCBiYWRnZUNsYXNzRGF0YV0pOw0KLy9JUkkgbXVzdCBiZSB1bmlxdWUgKHdlIGFsbG93IHRoZSBjcmVhdG9yIHRvIHVwZGF0ZSBpdCkNCmlmIChjcmVhdGVkLnJvd0NvdW50ID09PSAwKSB7DQogICAgcmV0dXJuICJCYWRnZSBjbGFzcyB3aXRoIHRoaXMgaWQgYWxyZWFkeSBleGlzdHMsIHVzZSBhIGRpZmZlcmVudCBpZC4iOw0KfQ0KcmV0dXJuICJPSyI7
Init as text:
await query("CREATE", "badgeclasses", "(id VARCHAR(256) PRIMARY KEY, " +
"entity VARCHAR(35) NOT NULL REFERENCES entities(entity), json JSON NOT NULL, data TEXT);", []);
Code as text:
let badgeClassData;
let badgeClassJson = JSON.parse(payload.badgeClass);
//Signed badge class
if (badgeClassJson === undefined || typeof badgeClassJson.payload === "string") {
let badgeClass;
if (badgeClassJson === undefined) {
//If it is in compact jws serialization format (base64urlAlgorithm.base64urlBadgeClass.base64urlSignature)
badgeClassData = payload.badgeClass;
badgeClass = badgeClassData.split(".")[1];
if (badgeClass === undefined) {
return "Signed badge class has invalid jws compact serialization format.";
}
}
else {
//If it is in json serialization format ({"payload":"base64urlBadgeClass", ...})
badgeClassData = badgeClassJson;
badgeClass = badgeClassJson.payload;
}
//jws uses base64url instead of base64 encoding, change it back.
badgeClass = badgeClass.replace(/-/g, "+").replace(/_/g, "/");
while ((badgeClass.length & 0x3) !== 0) {
badgeClass += "=";
}
if (badgeClass.search(/^[\+\/-9A-Za-z]*={0,2}$/) !== 0) {
return "Signed badge class is not base64url encoded.";
}
//Extract the json badge class
badgeClassJson = JSON.parse(Buffer.from(badgeClass, "base64").toString());
}
if (typeof badgeClassJson !== "object" || badgeClassJson === null) {
return "Badge class is invalid json.";
}
const badgeClassId = badgeClassJson.id || badgeClassJson["@id"];
if (typeof badgeClassId !== "string" || badgeClassId.length === 0 || badgeClassId.length > 256) {
return "Badge class is missing or has invalid id.";
}
//Not really needed to check this with signed verification, but we do not want someone to create someone else's badgeclass
const issuer = badgeClassJson.issuer || badgeClassJson["obi:issuer"] || badgeClassJson["https://w3id.org/openbadges#issuer"];
if (typeof issuer !== "string" && typeof issuer !== "object" || issuer === null) {
return "Badge class is missing or has invalid issuer.";
}
const issuerId = typeof issuer === "string" ? issuer : issuer.id || issuer["@id"];
if (typeof issuerId !== "string") {
return "Badge class is missing or has invalid issuer id.";
}
//Check if the entity exists and is not revoked.
const entity = (await query("SELECT", "entities", "WHERE entity = $1;", [from])).rows[0];
if (entity === undefined) {
return "Entity does not exists or user is not an entity.";
}
if (entity.revoked !== null) {
return "Entity is withdrawn.";
}
//Check if the institution is not withdrawn (we are sure it exists if the entity exists)
const institution = (await query("SELECT", "institutions", "WHERE institution = $1;", [entity.institution])).rows[0];
if (institution.revoked !== null) {
return "Institution of entity is withdrawn.";
}
else if (institution.iri !== issuerId) {
return "Institution is not the issuer for this badge class.";
}
//Create the badge. Note that it may not be valid, but that is for the checker service to resolve.
const created = await query("INSERT", "badgeclasses", "(id, entity, json, data) VALUES ($1, $2, $3, $4) " +
"ON CONFLICT ON CONSTRAINT badgeclasses_pkey DO UPDATE SET json = $3, data = $4 WHERE badgeclasses.entity = $2;", [badgeClassId, from, JSON.stringify(badgeClassJson), badgeClassData]);
//IRI must be unique (we allow the creator to update it)
if (created.rowCount === 0) {
return "Badge class with this id already exists, use a different id.";
}
return "OK";