@thezelijah/majik-message 1.0.5 → 1.0.6
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.
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MajikMessageIdentityJSON } from "../database/system/identity";
|
|
1
2
|
import { ISODateString } from "../types";
|
|
2
3
|
export type SerializedMajikContact = Omit<MajikContactData, "publicKey"> & {
|
|
3
4
|
publicKeyBase64: string;
|
|
@@ -48,6 +49,18 @@ export declare class MajikContact {
|
|
|
48
49
|
setBlocked(blocked: boolean): this;
|
|
49
50
|
block(): this;
|
|
50
51
|
unblock(): this;
|
|
52
|
+
/**
|
|
53
|
+
* Support both CryptoKey and raw-key wrappers (fallbacks when WebCrypto X25519 unsupported)
|
|
54
|
+
*/
|
|
55
|
+
getPublicKeyBase64(): Promise<string>;
|
|
51
56
|
toJSON(): Promise<SerializedMajikContact>;
|
|
57
|
+
/**
|
|
58
|
+
* Reconstruct a MajikContact from its serialized form
|
|
59
|
+
*/
|
|
60
|
+
static fromJSON(serialized: SerializedMajikContact): MajikContact;
|
|
61
|
+
/**
|
|
62
|
+
* Create a new MajikContact from a MajikMessageIdentityJSON
|
|
63
|
+
*/
|
|
64
|
+
static fromIdentityJSON(identityJSON: MajikMessageIdentityJSON): Promise<MajikContact>;
|
|
52
65
|
static isBlocked(contact: MajikContact): boolean;
|
|
53
66
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { arrayBufferToBase64 } from "../utils/utilities";
|
|
1
|
+
import { arrayBufferToBase64, base64ToArrayBuffer } from "../utils/utilities";
|
|
2
2
|
/* -------------------------------
|
|
3
3
|
* Errors
|
|
4
4
|
* ------------------------------- */
|
|
@@ -103,32 +103,72 @@ export class MajikContact {
|
|
|
103
103
|
this.setBlocked(false);
|
|
104
104
|
return this;
|
|
105
105
|
}
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Support both CryptoKey and raw-key wrappers (fallbacks when WebCrypto X25519 unsupported)
|
|
108
|
+
*/
|
|
109
|
+
async getPublicKeyBase64() {
|
|
108
110
|
try {
|
|
109
111
|
// If it's a CryptoKey, export with SubtleCrypto
|
|
110
112
|
const raw = await crypto.subtle.exportKey("raw", this.publicKey);
|
|
111
|
-
return
|
|
112
|
-
id: this.id,
|
|
113
|
-
fingerprint: this.fingerprint,
|
|
114
|
-
meta: { ...this.meta },
|
|
115
|
-
publicKeyBase64: arrayBufferToBase64(raw),
|
|
116
|
-
};
|
|
113
|
+
return arrayBufferToBase64(raw);
|
|
117
114
|
}
|
|
118
115
|
catch (e) {
|
|
119
116
|
// Fallback: publicKey may be a wrapper with `raw` Uint8Array
|
|
120
117
|
const maybe = this.publicKey;
|
|
121
118
|
if (maybe && maybe.raw instanceof Uint8Array) {
|
|
122
|
-
return
|
|
123
|
-
id: this.id,
|
|
124
|
-
fingerprint: this.fingerprint,
|
|
125
|
-
meta: { ...this.meta },
|
|
126
|
-
publicKeyBase64: arrayBufferToBase64(maybe.raw.buffer),
|
|
127
|
-
};
|
|
119
|
+
return arrayBufferToBase64(maybe.raw.buffer);
|
|
128
120
|
}
|
|
129
121
|
throw e;
|
|
130
122
|
}
|
|
131
123
|
}
|
|
124
|
+
async toJSON() {
|
|
125
|
+
return {
|
|
126
|
+
id: this.id,
|
|
127
|
+
fingerprint: this.fingerprint,
|
|
128
|
+
meta: { ...this.meta },
|
|
129
|
+
publicKeyBase64: await this.getPublicKeyBase64(),
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Reconstruct a MajikContact from its serialized form
|
|
134
|
+
*/
|
|
135
|
+
static fromJSON(serialized) {
|
|
136
|
+
try {
|
|
137
|
+
const publicKeyRaw = new Uint8Array(base64ToArrayBuffer(serialized.publicKeyBase64));
|
|
138
|
+
return new MajikContact({
|
|
139
|
+
id: serialized.id,
|
|
140
|
+
fingerprint: serialized.fingerprint,
|
|
141
|
+
meta: serialized.meta,
|
|
142
|
+
publicKey: { raw: publicKeyRaw },
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
throw new MajikContactError("Failed to deserialize MajikContact", err);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Create a new MajikContact from a MajikMessageIdentityJSON
|
|
151
|
+
*/
|
|
152
|
+
static async fromIdentityJSON(identityJSON) {
|
|
153
|
+
try {
|
|
154
|
+
const publicKeyRaw = new Uint8Array(base64ToArrayBuffer(identityJSON.public_key));
|
|
155
|
+
const contactData = {
|
|
156
|
+
id: identityJSON.id,
|
|
157
|
+
publicKey: { raw: publicKeyRaw },
|
|
158
|
+
fingerprint: identityJSON.id,
|
|
159
|
+
meta: {
|
|
160
|
+
label: identityJSON.label,
|
|
161
|
+
createdAt: identityJSON.timestamp,
|
|
162
|
+
updatedAt: identityJSON.timestamp,
|
|
163
|
+
blocked: identityJSON.restricted,
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
return new MajikContact(contactData);
|
|
167
|
+
}
|
|
168
|
+
catch (err) {
|
|
169
|
+
throw new MajikContactError("Failed to create MajikContact from MajikMessageIdentityJSON", err);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
132
172
|
static isBlocked(contact) {
|
|
133
173
|
return !!contact.meta.blocked;
|
|
134
174
|
}
|
|
@@ -70,10 +70,11 @@ export class MajikMessageIdentity {
|
|
|
70
70
|
const generatedID = autogenerateID();
|
|
71
71
|
const timestamp = new Date().toISOString();
|
|
72
72
|
const phash = sha256(`${user.id}:${account.id}:${generatedID}`);
|
|
73
|
+
const publicKey = account.publicKeyBase64;
|
|
73
74
|
return new MajikMessageIdentity({
|
|
74
75
|
id: generatedID,
|
|
75
76
|
userId: user.id,
|
|
76
|
-
publicKey:
|
|
77
|
+
publicKey: publicKey,
|
|
77
78
|
phash,
|
|
78
79
|
label,
|
|
79
80
|
timestamp,
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@thezelijah/majik-message",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"description": "Encrypt and decrypt messages on any website. Secure chats with keypairs and seed-based accounts. Open source.",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.6",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"author": "Zelijah",
|
|
8
8
|
"main": "./dist/index.js",
|