@thezelijah/majik-message 1.1.1 → 1.1.3
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/dist/core/crypto/constants.d.ts +1 -0
- package/dist/core/crypto/constants.js +1 -0
- package/dist/core/crypto/crypto-provider.d.ts +1 -0
- package/dist/core/crypto/crypto-provider.js +4 -1
- package/dist/core/crypto/keystore.d.ts +2 -0
- package/dist/core/crypto/keystore.js +16 -3
- package/dist/core/database/thread/enums.d.ts +7 -0
- package/dist/core/database/thread/enums.js +6 -0
- package/dist/core/database/thread/mail/majik-message-mail.d.ts +177 -0
- package/dist/core/database/thread/mail/majik-message-mail.js +704 -0
- package/dist/core/database/thread/majik-message-thread.d.ts +166 -0
- package/dist/core/database/thread/majik-message-thread.js +637 -0
- package/dist/core/types.d.ts +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/majik-message.js +23 -21
- package/package.json +6 -1
- package/dist/core/database/system/majik-user/enums.d.ts +0 -44
- package/dist/core/database/system/majik-user/enums.js +0 -40
- package/dist/core/database/system/majik-user/majik-user.d.ts +0 -261
- package/dist/core/database/system/majik-user/majik-user.js +0 -839
- package/dist/core/database/system/majik-user/types.d.ts +0 -186
- package/dist/core/database/system/majik-user/types.js +0 -1
- package/dist/core/database/system/majik-user/utils.d.ts +0 -32
- package/dist/core/database/system/majik-user/utils.js +0 -110
|
@@ -18,3 +18,4 @@ export declare function aesGcmDecrypt(keyBytes: Uint8Array, iv: Uint8Array, ciph
|
|
|
18
18
|
export declare function deriveKeyFromPassphrase(passphrase: string, salt: Uint8Array, iterations?: number, keyLen?: number): Uint8Array;
|
|
19
19
|
export declare function deriveKeyFromMnemonic(mnemonic: string, salt: Uint8Array, iterations?: number, keyLen?: number): Uint8Array;
|
|
20
20
|
export declare function x25519SharedSecret(privRaw: Uint8Array, pubRaw: Uint8Array): Uint8Array;
|
|
21
|
+
export declare function sha256(input: string): string;
|
|
@@ -57,7 +57,6 @@ export function deriveKeyFromMnemonic(mnemonic, salt, iterations = 200000, keyLe
|
|
|
57
57
|
return deriveKey(SHA256, m, salt, iterations, keyLen);
|
|
58
58
|
}
|
|
59
59
|
export function x25519SharedSecret(privRaw, pubRaw) {
|
|
60
|
-
// Use @stablelib/x25519 for scalar multiplication / shared secret
|
|
61
60
|
const priv = new Uint8Array(privRaw);
|
|
62
61
|
const pub = new Uint8Array(pubRaw);
|
|
63
62
|
if (x25519.scalarMult) {
|
|
@@ -68,3 +67,7 @@ export function x25519SharedSecret(privRaw, pubRaw) {
|
|
|
68
67
|
}
|
|
69
68
|
throw new Error("@stablelib/x25519: compatible API not found");
|
|
70
69
|
}
|
|
70
|
+
export function sha256(input) {
|
|
71
|
+
const hashed = hash(new TextEncoder().encode(input));
|
|
72
|
+
return arrayToBase64(hashed);
|
|
73
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { MajikKey } from "@thezelijah/majik-key";
|
|
1
2
|
export interface KeyStoreIdentity {
|
|
2
3
|
id: string;
|
|
3
4
|
publicKey: CryptoKey | {
|
|
@@ -39,6 +40,7 @@ export declare class KeyStore {
|
|
|
39
40
|
static onUnlockRequested?: (id: string) => string | Promise<string>;
|
|
40
41
|
static init(deviceID: string): void;
|
|
41
42
|
private static getDB;
|
|
43
|
+
static addMajikKey(key: MajikKey): Promise<void>;
|
|
42
44
|
private static putSerializedIdentity;
|
|
43
45
|
private static getSerializedIdentity;
|
|
44
46
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { arrayBufferToBase64, base64ToArrayBuffer, base64ToUtf8, utf8ToBase64, concatUint8Arrays, arrayToBase64, } from "../utils/utilities";
|
|
2
|
-
import { KEY_ALGO, MAJIK_SALT } from "./constants";
|
|
2
|
+
import { KEY_ALGO, MAJIK_MNEMONIC_SALT, MAJIK_SALT } from "./constants";
|
|
3
3
|
import { EncryptionEngine } from "./encryption-engine";
|
|
4
4
|
import { generateMnemonic } from "@scure/bip39";
|
|
5
5
|
import { wordlist } from "@scure/bip39/wordlists/english";
|
|
@@ -60,6 +60,19 @@ export class KeyStore {
|
|
|
60
60
|
});
|
|
61
61
|
return this.dbPromise;
|
|
62
62
|
}
|
|
63
|
+
static async addMajikKey(key) {
|
|
64
|
+
const serializedIdentity = key.toSerializedIdentity();
|
|
65
|
+
const keyIdentity = key.toKeyIdentity();
|
|
66
|
+
this.unlockedIdentities.set(keyIdentity.id, keyIdentity);
|
|
67
|
+
const db = await this.getDB();
|
|
68
|
+
return new Promise((resolve, reject) => {
|
|
69
|
+
const tx = db.transaction(this.STORE_NAME, "readwrite");
|
|
70
|
+
const store = tx.objectStore(this.STORE_NAME);
|
|
71
|
+
const req = store.put(serializedIdentity);
|
|
72
|
+
req.onsuccess = () => resolve();
|
|
73
|
+
req.onerror = () => reject(new KeyStoreError("Failed to store identity", req.error));
|
|
74
|
+
});
|
|
75
|
+
}
|
|
63
76
|
static async putSerializedIdentity(identity) {
|
|
64
77
|
const db = await this.getDB();
|
|
65
78
|
return new Promise((resolve, reject) => {
|
|
@@ -493,7 +506,7 @@ export class KeyStore {
|
|
|
493
506
|
}
|
|
494
507
|
}
|
|
495
508
|
// Derive AES key from mnemonic using Stablelib provider
|
|
496
|
-
const salt = new TextEncoder().encode(
|
|
509
|
+
const salt = new TextEncoder().encode(MAJIK_MNEMONIC_SALT);
|
|
497
510
|
const keyBytes = providerDeriveKeyFromMnemonic(mnemonic, salt);
|
|
498
511
|
const iv = generateRandomBytes(IV_LENGTH);
|
|
499
512
|
const ciphertext = aesGcmEncrypt(keyBytes, iv, new Uint8Array(privRawBuf));
|
|
@@ -571,7 +584,7 @@ export class KeyStore {
|
|
|
571
584
|
}
|
|
572
585
|
}
|
|
573
586
|
static async deriveKeyFromMnemonic(mnemonic) {
|
|
574
|
-
const salt = new TextEncoder().encode(
|
|
587
|
+
const salt = new TextEncoder().encode(MAJIK_MNEMONIC_SALT);
|
|
575
588
|
const keyMaterial = await crypto.subtle.importKey("raw", new TextEncoder().encode(mnemonic), { name: "PBKDF2" }, false, ["deriveKey"]);
|
|
576
589
|
return crypto.subtle.deriveKey({
|
|
577
590
|
name: "PBKDF2",
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const ThreadStatus: {
|
|
2
|
+
readonly ONGOING: "ongoing";
|
|
3
|
+
readonly CLOSED: "closed";
|
|
4
|
+
readonly PENDING_DELETION: "pending_deletion";
|
|
5
|
+
readonly MARKED_FOR_DELETION: "marked_for_deletion";
|
|
6
|
+
};
|
|
7
|
+
export type ThreadStatus = (typeof ThreadStatus)[keyof typeof ThreadStatus];
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { ISODateString, MajikMessageAccountID, MajikMessageMailID, MajikMessagePublicKey, MajikMessageThreadID } from "../../../types";
|
|
2
|
+
import { MajikMessageIdentity } from "../../system/identity";
|
|
3
|
+
import { MajikMessageThread } from "../majik-message-thread";
|
|
4
|
+
export interface MailMetadata {
|
|
5
|
+
subject?: string;
|
|
6
|
+
attachments?: string[];
|
|
7
|
+
priority?: "low" | "medium" | "high" | "urgent";
|
|
8
|
+
labels?: string[];
|
|
9
|
+
isForwarded?: boolean;
|
|
10
|
+
isReply?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface MajikMessageMailJSON {
|
|
13
|
+
id: MajikMessageMailID;
|
|
14
|
+
thread_id: MajikMessageThreadID;
|
|
15
|
+
account: MajikMessageAccountID;
|
|
16
|
+
message: string;
|
|
17
|
+
sender: MajikMessagePublicKey;
|
|
18
|
+
recipients: MajikMessagePublicKey[];
|
|
19
|
+
timestamp: ISODateString;
|
|
20
|
+
metadata: MailMetadata;
|
|
21
|
+
hash: string;
|
|
22
|
+
p_hash: string;
|
|
23
|
+
previous_mail_id?: MajikMessageMailID;
|
|
24
|
+
read_by: MajikMessagePublicKey[];
|
|
25
|
+
}
|
|
26
|
+
export declare class MajikMailError extends Error {
|
|
27
|
+
code: string;
|
|
28
|
+
constructor(message: string, code: string);
|
|
29
|
+
}
|
|
30
|
+
export declare class MailValidationError extends MajikMailError {
|
|
31
|
+
constructor(message: string);
|
|
32
|
+
}
|
|
33
|
+
export declare class MailOperationError extends MajikMailError {
|
|
34
|
+
constructor(message: string);
|
|
35
|
+
}
|
|
36
|
+
export declare class HashIntegrityError extends MajikMailError {
|
|
37
|
+
constructor(message: string);
|
|
38
|
+
}
|
|
39
|
+
export declare class MajikMessageMail {
|
|
40
|
+
private readonly _id;
|
|
41
|
+
private readonly _threadID;
|
|
42
|
+
private readonly _account;
|
|
43
|
+
private _message;
|
|
44
|
+
private readonly _sender;
|
|
45
|
+
private _recipients;
|
|
46
|
+
private readonly _timestamp;
|
|
47
|
+
private _metadata;
|
|
48
|
+
private readonly _hash;
|
|
49
|
+
private readonly _p_hash;
|
|
50
|
+
private readonly _previousMailID?;
|
|
51
|
+
private _readBy;
|
|
52
|
+
private static readonly MAX_MESSAGE_LENGTH;
|
|
53
|
+
private constructor();
|
|
54
|
+
get id(): MajikMessageMailID;
|
|
55
|
+
get threadID(): MajikMessageThreadID;
|
|
56
|
+
get account(): MajikMessageAccountID;
|
|
57
|
+
get sender(): MajikMessagePublicKey;
|
|
58
|
+
get recipients(): readonly MajikMessagePublicKey[];
|
|
59
|
+
get timestamp(): Date;
|
|
60
|
+
get metadata(): Readonly<MailMetadata>;
|
|
61
|
+
get hash(): string;
|
|
62
|
+
get p_hash(): string;
|
|
63
|
+
get previousMailID(): MajikMessageMailID | undefined;
|
|
64
|
+
get readBy(): readonly MajikMessagePublicKey[];
|
|
65
|
+
get message(): string;
|
|
66
|
+
/**
|
|
67
|
+
* Creates the first mail item in a thread.
|
|
68
|
+
* Uses the thread's hash as the p_hash since this is the first item.
|
|
69
|
+
*
|
|
70
|
+
* @param thread - The MajikMessageThread this mail belongs to
|
|
71
|
+
* @param identity - The sender's MajikMessageIdentity
|
|
72
|
+
* @param message - Plain text message (encrypted)
|
|
73
|
+
* @param recipients - Array of recipient public keys (excluding sender)
|
|
74
|
+
* @param metadata - Optional mail metadata
|
|
75
|
+
* @returns Promise resolving to new MajikMessageMail instance
|
|
76
|
+
* @throws Error if validation fails or thread is closed
|
|
77
|
+
*/
|
|
78
|
+
static create(thread: MajikMessageThread, identity: MajikMessageIdentity, message: string, recipients: MajikMessagePublicKey[], metadata?: MailMetadata): Promise<MajikMessageMail>;
|
|
79
|
+
/**
|
|
80
|
+
* Creates a reply to an existing mail item in the thread.
|
|
81
|
+
* Uses the previous mail's hash as part of the p_hash.
|
|
82
|
+
*
|
|
83
|
+
* @param thread - The MajikMessageThread this mail belongs to
|
|
84
|
+
* @param previousMail - The mail being replied to
|
|
85
|
+
* @param identity - The sender's MajikMessageIdentity
|
|
86
|
+
* @param message - Plain text message (encrypted)
|
|
87
|
+
* @param recipients - Array of recipient public keys (excluding sender)
|
|
88
|
+
* @param metadata - Optional mail metadata
|
|
89
|
+
* @returns Promise resolving to new MajikMessageMail instance
|
|
90
|
+
* @throws Error if validation fails or thread is closed
|
|
91
|
+
*/
|
|
92
|
+
static reply(thread: MajikMessageThread, previousMail: MajikMessageMail, identity: MajikMessageIdentity, message: string, recipients: MajikMessagePublicKey[], metadata?: MailMetadata): Promise<MajikMessageMail>;
|
|
93
|
+
/**
|
|
94
|
+
* Generates the hash for the current mail item.
|
|
95
|
+
* Format: SHA256(id:message:sender:recipients:timestamp)
|
|
96
|
+
*/
|
|
97
|
+
private static generateHash;
|
|
98
|
+
/**
|
|
99
|
+
* Generates the previous hash (blockchain link).
|
|
100
|
+
* Format: SHA256(currentHash:previousHash)
|
|
101
|
+
*/
|
|
102
|
+
private static generatePHash;
|
|
103
|
+
/**
|
|
104
|
+
* Validates the current mail item's integrity.
|
|
105
|
+
* Checks hash and p_hash validity.
|
|
106
|
+
*/
|
|
107
|
+
validate(): boolean;
|
|
108
|
+
/**
|
|
109
|
+
* Validates the p_hash against a previous hash.
|
|
110
|
+
* Used to verify blockchain integrity.
|
|
111
|
+
*
|
|
112
|
+
* @param previousHash - The hash from the previous item (or thread hash for first item)
|
|
113
|
+
* @returns true if p_hash is valid
|
|
114
|
+
*/
|
|
115
|
+
validatePHash(previousHash: string): boolean;
|
|
116
|
+
private validateMessage;
|
|
117
|
+
/**
|
|
118
|
+
* Validates an entire chain of mail items in a thread.
|
|
119
|
+
* Verifies both hash and p_hash integrity for all items.
|
|
120
|
+
*
|
|
121
|
+
* @param thread - The thread these mail items belong to
|
|
122
|
+
* @param mailItems - Array of mail items ordered chronologically (oldest first)
|
|
123
|
+
* @returns Validation result with details
|
|
124
|
+
*/
|
|
125
|
+
static validateMailChain(thread: MajikMessageThread, mailItems: MajikMessageMail[]): {
|
|
126
|
+
isValid: boolean;
|
|
127
|
+
errors: string[];
|
|
128
|
+
tamperedItems: string[];
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Marks this mail as read by a recipient.
|
|
132
|
+
* @param recipientPublicKey - The public key of the recipient marking as read
|
|
133
|
+
* @returns true if successfully marked, false if already read
|
|
134
|
+
*/
|
|
135
|
+
markAsRead(recipientPublicKey: MajikMessagePublicKey): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Checks if a specific user has read this mail.
|
|
138
|
+
*/
|
|
139
|
+
hasUserRead(recipientPublicKey: MajikMessagePublicKey): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Checks if all recipients have read this mail.
|
|
142
|
+
*/
|
|
143
|
+
isReadByAll(): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Gets the list of recipients who haven't read this mail yet.
|
|
146
|
+
*/
|
|
147
|
+
getUnreadRecipients(): MajikMessagePublicKey[];
|
|
148
|
+
/**
|
|
149
|
+
* Gets the read percentage.
|
|
150
|
+
*/
|
|
151
|
+
getReadPercentage(): number;
|
|
152
|
+
/**
|
|
153
|
+
* Checks if a user can access this mail (is sender or recipient).
|
|
154
|
+
*/
|
|
155
|
+
canUserAccess(userPublicKey: MajikMessagePublicKey): boolean;
|
|
156
|
+
/**
|
|
157
|
+
* Checks if a user is the sender of this mail.
|
|
158
|
+
*/
|
|
159
|
+
isSender(userPublicKey: MajikMessagePublicKey): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Checks if a user is a recipient of this mail.
|
|
162
|
+
*/
|
|
163
|
+
isRecipient(userPublicKey: MajikMessagePublicKey): boolean;
|
|
164
|
+
/**
|
|
165
|
+
* Updates the metadata for this mail.
|
|
166
|
+
*/
|
|
167
|
+
updateMetadata(metadata: Partial<MailMetadata>): void;
|
|
168
|
+
toJSON(): MajikMessageMailJSON;
|
|
169
|
+
static fromJSON(json: MajikMessageMailJSON | string): MajikMessageMail;
|
|
170
|
+
toString(): string;
|
|
171
|
+
clone(): MajikMessageMail;
|
|
172
|
+
/**
|
|
173
|
+
* Validates raw message length
|
|
174
|
+
*/
|
|
175
|
+
private static validateRawMessageLength;
|
|
176
|
+
private static isValidJSON;
|
|
177
|
+
}
|