memdeklaro-js 1.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 +39 -0
- package/example_photo.jpg +0 -0
- package/example_signature.jpg +0 -0
- package/memdeklaro.js +172 -0
- package/package.json +26 -0
- package/template_back.jpg +0 -0
- package/template_background.jpg +0 -0
- package/template_front.jpg +0 -0
- package/template_pdf.jpg +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# memdeklaro.js
|
|
2
|
+
|
|
3
|
+
An offline CLI tool to generate a Memdeklaro Self-Declaration of Identity
|
|
4
|
+
|
|
5
|
+
Memdeklaro is a non-government non-corporate foundation for ethical decentralized identity. The project website is available at [https://memdeklaro.org](https://memdeklaro.org)
|
|
6
|
+
|
|
7
|
+
## How to use
|
|
8
|
+
|
|
9
|
+
`npm install memdeklaro-js`
|
|
10
|
+
|
|
11
|
+
Then
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
node memdeklaro.js \
|
|
15
|
+
--firstname "John" \
|
|
16
|
+
--surname "Doe" \
|
|
17
|
+
--birthdate "1989-12-31" \
|
|
18
|
+
--note "Conscientious Objector" \
|
|
19
|
+
--number "1234567890" \
|
|
20
|
+
--issued "2026-01-23" \
|
|
21
|
+
--expiry "2031-01-23" \
|
|
22
|
+
--issuer "EPO" \
|
|
23
|
+
--photo example_photo.jpg \
|
|
24
|
+
--signature example_signature.jpg
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## What you get
|
|
28
|
+
|
|
29
|
+
- Your Memdeklaro decentralized ID card to print or use digitally: memdeklaro_front.jpg and memdeklaro_back.jpg
|
|
30
|
+
- A self-asserted verifiable credential that you can optionally sign with your DID key and import into your web3 wallet: memdeklaro.json
|
|
31
|
+
- A PDF that includes your self-declaration in graphical format and as a QR code to import into Google Wallet or Apple Wallet: memdeklaro.pdf
|
|
32
|
+
|
|
33
|
+
## Similar projects
|
|
34
|
+
|
|
35
|
+
Similar projects include the World Passport, Digitalcourage Lichtbildausweis and Bitnation.
|
|
36
|
+
|
|
37
|
+
## License
|
|
38
|
+
|
|
39
|
+
Public Domain, see [https://memdeklaro.org/about/](https://memdeklaro.org/about/) for more details
|
|
Binary file
|
|
Binary file
|
package/memdeklaro.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import minimist from "minimist";
|
|
4
|
+
import { createCanvas, loadImage, registerFont } from "canvas";
|
|
5
|
+
import { writeFileSync } from "fs";
|
|
6
|
+
import { generate } from "lean-qr";
|
|
7
|
+
import { toPngDataURL } from 'lean-qr/extras/node_export';
|
|
8
|
+
import { transliterate } from "transliteration";
|
|
9
|
+
|
|
10
|
+
function checksum(str) {
|
|
11
|
+
var counter = 0;
|
|
12
|
+
var total = 0;
|
|
13
|
+
for(var i = 0; i < str.length; i++) {
|
|
14
|
+
if(counter == 3) {
|
|
15
|
+
var counter = 0;
|
|
16
|
+
}
|
|
17
|
+
if(counter == 0) {
|
|
18
|
+
var total = total + (parseInt(str[i]) * 7);
|
|
19
|
+
}
|
|
20
|
+
if(counter == 1) {
|
|
21
|
+
var total = total + (parseInt(str[i]) * 3);
|
|
22
|
+
}
|
|
23
|
+
if(counter == 2) {
|
|
24
|
+
var total = total + (parseInt(str[i]) * 1);
|
|
25
|
+
}
|
|
26
|
+
counter++;
|
|
27
|
+
}
|
|
28
|
+
var check_digit = total % 10;
|
|
29
|
+
return check_digit;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function generate_memdeklaro_self_declaration() {
|
|
33
|
+
|
|
34
|
+
var params = minimist(process.argv.slice(2));
|
|
35
|
+
|
|
36
|
+
var surname = params.surname;
|
|
37
|
+
var first_name = params.firstname;
|
|
38
|
+
var birth_date = params.birthdate;
|
|
39
|
+
var issued = params.issued;
|
|
40
|
+
var expiry = params.expiry;
|
|
41
|
+
var id_number = params.number;
|
|
42
|
+
var note = params.note;
|
|
43
|
+
var issuer = params.issuer;
|
|
44
|
+
var photo = params.photo;
|
|
45
|
+
var signature = params.signature;
|
|
46
|
+
|
|
47
|
+
var did = {
|
|
48
|
+
"@context": [
|
|
49
|
+
"https://www.w3.org/ns/credentials/v2"
|
|
50
|
+
],
|
|
51
|
+
"type": ["VerifiableCredential", "IDCard"],
|
|
52
|
+
"issuer": {
|
|
53
|
+
"id": "did:web:memdeklaro.org"
|
|
54
|
+
},
|
|
55
|
+
"identifier": id_number,
|
|
56
|
+
"name": "Memdeklaro ID",
|
|
57
|
+
"description": "Self-Declaration of Identity",
|
|
58
|
+
"validFrom": issued+"T00:00:00Z",
|
|
59
|
+
"validUntil": expiry+"T00:00:00Z",
|
|
60
|
+
"credentialSubject": {
|
|
61
|
+
"type": ["Person"],
|
|
62
|
+
"givenName": first_name,
|
|
63
|
+
"familyName": surname,
|
|
64
|
+
"birthDate": birth_date,
|
|
65
|
+
"note": note
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
writeFileSync("memdeklaro.json", JSON.stringify(did));
|
|
70
|
+
|
|
71
|
+
var mr_first_name = transliterate(first_name).replace(/[\-\ ]/g, "<").normalize("NFD").replace(/[^A-Z\<]/gi, "").toUpperCase();
|
|
72
|
+
var mr_surname = transliterate(surname).replace(/[\-\ ]/g, "<").normalize("NFD").replace(/[^A-Z\<]/gi, "").toUpperCase();
|
|
73
|
+
var mr_issuer = transliterate(issuer).replace(/[\-\ ]/g, "<").normalize("NFD").replace(/[^A-Z\<]/gi, "").toUpperCase().slice(0,3);
|
|
74
|
+
var mr_id_number = id_number;
|
|
75
|
+
var mr_birth_date = birth_date.split("-").join("").substring(2);
|
|
76
|
+
var mr_expiry = expiry.split("-").join("").substring(2);
|
|
77
|
+
|
|
78
|
+
var mrz_checksum = checksum(mr_id_number + checksum(mr_id_number) + mr_birth_date + checksum(mr_birth_date) + mr_expiry + checksum(mr_expiry));
|
|
79
|
+
var mrz1 = "I<" + mr_issuer + mr_id_number + checksum(mr_id_number) + "<<<<<<<<<<<<<<";
|
|
80
|
+
var mrz2 = mr_birth_date + checksum(mr_birth_date) + "<" + mr_expiry + checksum(mr_expiry) + "<<<<<<<<<<<<<<" + mrz_checksum;
|
|
81
|
+
var mrz3 = mr_surname + "<<" + mr_first_name;
|
|
82
|
+
if(mrz3.length >= 30) { var mrz3 = mrz3.slice(0, 29); }
|
|
83
|
+
while(mrz3.length < 30) { var mrz3 = mrz3 + "<"; }
|
|
84
|
+
var mrz = mrz1 + "\r\n" + mrz2 + "\r\n" + mrz3;
|
|
85
|
+
|
|
86
|
+
// Not working, falling back to monospace
|
|
87
|
+
// registerFont("OCR-B.ttf", { family: "OCR-B" });
|
|
88
|
+
|
|
89
|
+
var canvas_front = createCanvas(2022, 1275);
|
|
90
|
+
var ctx_front = canvas_front.getContext("2d");
|
|
91
|
+
|
|
92
|
+
var img_front = await loadImage("template_front.jpg");
|
|
93
|
+
|
|
94
|
+
ctx_front.drawImage(img_front, 0, 0, 2022, 1275);
|
|
95
|
+
|
|
96
|
+
ctx_front.font = "bold 75px monospace";
|
|
97
|
+
ctx_front.fillText(surname.toUpperCase(), 855, 385);
|
|
98
|
+
ctx_front.fillText(first_name.toUpperCase(), 855, 565);
|
|
99
|
+
|
|
100
|
+
ctx_front.font = "bold 65px monospace";
|
|
101
|
+
ctx_front.fillText(birth_date, 855, 735);
|
|
102
|
+
ctx_front.fillText(issued, 855, 915);
|
|
103
|
+
ctx_front.fillText(expiry, 1415, 915);
|
|
104
|
+
ctx_front.fillText(id_number, 1415, 1095);
|
|
105
|
+
|
|
106
|
+
var img_photo = await loadImage(photo);
|
|
107
|
+
|
|
108
|
+
ctx_front.drawImage(img_photo, 58, 260, 745, 956);
|
|
109
|
+
|
|
110
|
+
var img_signature = await loadImage(signature);
|
|
111
|
+
|
|
112
|
+
ctx_front.globalCompositeOperation = "multiply";
|
|
113
|
+
ctx_front.drawImage(img_signature, 870, 1055, Math.round(img_signature.width * (150 / img_signature.height)), 150);
|
|
114
|
+
ctx_front.globalCompositeOperation = "source-over";
|
|
115
|
+
|
|
116
|
+
writeFileSync("memdeklaro_front.jpg", canvas_front.toBuffer("image/jpeg", { quality: 1 }));
|
|
117
|
+
|
|
118
|
+
var canvas_back = createCanvas(2022, 1275);
|
|
119
|
+
var ctx_back = canvas_back.getContext("2d");
|
|
120
|
+
|
|
121
|
+
var img_back = await loadImage("template_back.jpg");
|
|
122
|
+
|
|
123
|
+
ctx_back.drawImage(img_back, 0, 0, 2022, 1275);
|
|
124
|
+
|
|
125
|
+
ctx_back.font = "bold 65px monospace";
|
|
126
|
+
|
|
127
|
+
var note_lines = note.split("\n");
|
|
128
|
+
for(var i = 0; i < note_lines.length; i++) {
|
|
129
|
+
ctx_back.fillText(note_lines[i].toUpperCase(), 55, 200 + (75 * i));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
ctx_back.fillText(issuer.toUpperCase(), 55, 460);
|
|
133
|
+
|
|
134
|
+
ctx_back.font = "bold 85px monospace";
|
|
135
|
+
|
|
136
|
+
var mrz_lines = mrz.split("\n");
|
|
137
|
+
for(var i = 0; i < mrz_lines.length; i++) {
|
|
138
|
+
ctx_back.fillText(mrz_lines[i], 235, 925 + (100 * i));
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
writeFileSync("memdeklaro_back.jpg", canvas_back.toBuffer("image/jpeg", { quality: 1 }));
|
|
142
|
+
|
|
143
|
+
var canvas_pdf = createCanvas(2480, 3508, "pdf");
|
|
144
|
+
var ctx_pdf = canvas_pdf.getContext("2d");
|
|
145
|
+
|
|
146
|
+
var img_pdf = await loadImage("template_pdf.jpg");
|
|
147
|
+
|
|
148
|
+
ctx_pdf.drawImage(img_pdf, 0, 0, 2480, 3508);
|
|
149
|
+
|
|
150
|
+
var img_front_copy = await loadImage(canvas_front.toDataURL());
|
|
151
|
+
|
|
152
|
+
ctx_pdf.drawImage(img_front_copy, 734, 620, 1012, 638);
|
|
153
|
+
|
|
154
|
+
var img_back_copy = await loadImage(canvas_back.toDataURL());
|
|
155
|
+
|
|
156
|
+
ctx_pdf.drawImage(img_back_copy, 734, 1466, 1012, 638);
|
|
157
|
+
|
|
158
|
+
var qr_code = generate(JSON.stringify(did));
|
|
159
|
+
|
|
160
|
+
var export_qr_code = toPngDataURL(qr_code, { scale: 4 });
|
|
161
|
+
|
|
162
|
+
var img_qr_code = await loadImage(export_qr_code);
|
|
163
|
+
|
|
164
|
+
ctx_pdf.drawImage(img_qr_code, 840, 2303, 800, 800);
|
|
165
|
+
|
|
166
|
+
writeFileSync("memdeklaro.pdf", canvas_pdf.toBuffer("application/pdf", { title: "Memdeklaro", creationDate: new Date() }));
|
|
167
|
+
|
|
168
|
+
return true;
|
|
169
|
+
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
await generate_memdeklaro_self_declaration();
|
package/package.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "memdeklaro-js",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "An offline CLI tool to generate a Memdeklaro Self-Declaration of Identity",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"decentralized-identity",
|
|
7
|
+
"self-sovereign-identity",
|
|
8
|
+
"web3",
|
|
9
|
+
"esperanto",
|
|
10
|
+
"memdeklaro"
|
|
11
|
+
],
|
|
12
|
+
"homepage": "https://memdeklaro.org/",
|
|
13
|
+
"license": "Unlicense",
|
|
14
|
+
"author": "Memdeklaro",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "memdeklaro.js",
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"canvas": "^3.2.3",
|
|
22
|
+
"lean-qr": "^2.7.4",
|
|
23
|
+
"minimist": "^1.2.8",
|
|
24
|
+
"transliteration": "^2.6.1"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/template_pdf.jpg
ADDED
|
Binary file
|