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 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
Binary file