@majikah/majik-key 0.1.1
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/LICENSE +67 -0
- package/README.md +911 -0
- package/dist/core/crypto/constants.d.ts +6 -0
- package/dist/core/crypto/constants.js +3 -0
- package/dist/core/crypto/crypto-provider.d.ts +21 -0
- package/dist/core/crypto/crypto-provider.js +74 -0
- package/dist/core/crypto/encryption-engine.d.ts +36 -0
- package/dist/core/crypto/encryption-engine.js +114 -0
- package/dist/core/database/system/identity.d.ts +61 -0
- package/dist/core/database/system/identity.js +171 -0
- package/dist/core/error.d.ts +4 -0
- package/dist/core/error.js +11 -0
- package/dist/core/majik-contact.d.ts +72 -0
- package/dist/core/majik-contact.js +195 -0
- package/dist/core/types.d.ts +19 -0
- package/dist/core/types.js +1 -0
- package/dist/core/utils.d.ts +28 -0
- package/dist/core/utils.js +107 -0
- package/dist/core/validator.d.ts +10 -0
- package/dist/core/validator.js +80 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/majik-key.d.ts +269 -0
- package/dist/majik-key.js +763 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,911 @@
|
|
|
1
|
+
# Majik Key
|
|
2
|
+
|
|
3
|
+
[](https://thezelijah.world) 
|
|
4
|
+
|
|
5
|
+
**Majik Key** is a seed phrase account library for creating, managing, and parsing mnemonic-based cryptographic accounts (Majik Keys). Generate deterministic key pairs from BIP39 seed phrases with simple, developer-friendly APIs.
|
|
6
|
+
|
|
7
|
+
   [](https://opensource.org/licenses/Apache-2.0) 
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
- [Majik Key](#majik-key)
|
|
13
|
+
- [Overview](#overview)
|
|
14
|
+
- [What is a Majik Key?](#what-is-a-majik-key)
|
|
15
|
+
- [Use Cases](#use-cases)
|
|
16
|
+
- [Features](#features)
|
|
17
|
+
- [Security First](#security-first)
|
|
18
|
+
- [BIP39 Compliance](#bip39-compliance)
|
|
19
|
+
- [Developer Friendly](#developer-friendly)
|
|
20
|
+
- [Import/Export](#importexport)
|
|
21
|
+
- [Interoperability](#interoperability)
|
|
22
|
+
- [Installation](#installation)
|
|
23
|
+
- [Quick Start](#quick-start)
|
|
24
|
+
- [API Reference](#api-reference)
|
|
25
|
+
- [Static Methods](#static-methods)
|
|
26
|
+
- [`MajikKey.create(mnemonic, passphrase, label?)`](#majikkeycreatemnemonic-passphrase-label)
|
|
27
|
+
- [`MajikKey.fromJSON(json)`](#majikkeyfromjsonjson)
|
|
28
|
+
- [`MajikKey.fromMnemonicJSON(mnemonicJson, passphrase, label?)`](#majikkeyfrommnemonicjsonmnemonicjson-passphrase-label)
|
|
29
|
+
- [`MajikKey.importFromMnemonicBackup(backup, mnemonic, passphrase, label?)`](#majikkeyimportfrommnemonicbackupbackup-mnemonic-passphrase-label)
|
|
30
|
+
- [`MajikKey.generateMnemonic(strength?)`](#majikkeygeneratemnemonicstrength)
|
|
31
|
+
- [`MajikKey.validateMnemonic(mnemonic)`](#majikkeyvalidatemnemonicmnemonic)
|
|
32
|
+
- [Instance Methods](#instance-methods)
|
|
33
|
+
- [`unlock(passphrase)`](#unlockpassphrase)
|
|
34
|
+
- [`lock()`](#lock)
|
|
35
|
+
- [`verify(passphrase)`](#verifypassphrase)
|
|
36
|
+
- [`updateLabel(newLabel)`](#updatelabelnewlabel)
|
|
37
|
+
- [`updatePassphrase(currentPassphrase, newPassphrase)`](#updatepassphrasecurrentpassphrase-newpassphrase)
|
|
38
|
+
- [`getPrivateKey()`](#getprivatekey)
|
|
39
|
+
- [`getPrivateKeyBase64()`](#getprivatekeybase64)
|
|
40
|
+
- [`toJSON()`](#tojson)
|
|
41
|
+
- [`toString(pretty?)`](#tostringpretty)
|
|
42
|
+
- [`toMnemonicJSON(mnemonic, passphrase?)`](#tomnemonicjsonmnemonic-passphrase)
|
|
43
|
+
- [`exportMnemonicBackup(mnemonic)`](#exportmnemonicbackupmnemonic)
|
|
44
|
+
- [`toContact()`](#tocontact)
|
|
45
|
+
- [`toMajikMessageIdentity(user, options?)`](#tomajikmessageidentityuser-options)
|
|
46
|
+
- [Getters](#getters)
|
|
47
|
+
- [`id: string`](#id-string)
|
|
48
|
+
- [`fingerprint: string`](#fingerprint-string)
|
|
49
|
+
- [`publicKey: CryptoKey | { raw: Uint8Array }`](#publickey-cryptokey---raw-uint8array-)
|
|
50
|
+
- [`publicKeyBase64: string`](#publickeybase64-string)
|
|
51
|
+
- [`label: string`](#label-string)
|
|
52
|
+
- [`backup: string`](#backup-string)
|
|
53
|
+
- [`timestamp: Date`](#timestamp-date)
|
|
54
|
+
- [`isLocked: boolean`](#islocked-boolean)
|
|
55
|
+
- [`isUnlocked: boolean`](#isunlocked-boolean)
|
|
56
|
+
- [`metadata: MajikKeyMetadata`](#metadata-majikkeymetadata)
|
|
57
|
+
- [Usage Examples](#usage-examples)
|
|
58
|
+
- [Example 1: Create and Manage a Key](#example-1-create-and-manage-a-key)
|
|
59
|
+
- [Example 2: Lock/Unlock Pattern](#example-2-lockunlock-pattern)
|
|
60
|
+
- [Example 3: Backup and Recovery](#example-3-backup-and-recovery)
|
|
61
|
+
- [Example 4: Update Passphrase](#example-4-update-passphrase)
|
|
62
|
+
- [Example 5: Verify Passphrase](#example-5-verify-passphrase)
|
|
63
|
+
- [Integration with Majik Message](#integration-with-majik-message)
|
|
64
|
+
- [Importing to Majik Message](#importing-to-majik-message)
|
|
65
|
+
- [Converting to Majik Message Identity](#converting-to-majik-message-identity)
|
|
66
|
+
- [Security Considerations](#security-considerations)
|
|
67
|
+
- [Best Practices](#best-practices)
|
|
68
|
+
- [Security Features](#security-features)
|
|
69
|
+
- [What NOT to Do](#what-not-to-do)
|
|
70
|
+
- [What TO Do](#what-to-do)
|
|
71
|
+
- [Tips \& Reminders](#tips--reminders)
|
|
72
|
+
- [For Developers](#for-developers)
|
|
73
|
+
- [For Users](#for-users)
|
|
74
|
+
- [Related Projects](#related-projects)
|
|
75
|
+
- [Majik Message](#majik-message)
|
|
76
|
+
- [Contributing](#contributing)
|
|
77
|
+
- [License](#license)
|
|
78
|
+
- [Author](#author)
|
|
79
|
+
- [About the Developer](#about-the-developer)
|
|
80
|
+
- [Contact](#contact)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Overview
|
|
86
|
+
|
|
87
|
+
**Majik Key** is a comprehensive library for managing seed phrase-based cryptographic accounts. It provides a secure, intuitive way to create, store, and manage mnemonic-based identities with built-in encryption, backup, and recovery features.
|
|
88
|
+
|
|
89
|
+
### What is a Majik Key?
|
|
90
|
+
|
|
91
|
+
A Majik Key is a seed phrase account that:
|
|
92
|
+
- Derives cryptographic key pairs from BIP39 mnemonic phrases
|
|
93
|
+
- Encrypts private keys at rest with a user-defined passphrase
|
|
94
|
+
- Supports secure backup and recovery via mnemonic encryption
|
|
95
|
+
- Provides locked/unlocked state management for enhanced security
|
|
96
|
+
- Is fully compatible with **Majik Message** and other Majikah products
|
|
97
|
+
|
|
98
|
+
### Use Cases
|
|
99
|
+
|
|
100
|
+
- **Majik Message Integration**: Create seed phrase accounts that can be imported directly into Majik Message
|
|
101
|
+
- **Cryptographic Identity Management**: Manage multiple identities with deterministic key derivation
|
|
102
|
+
- **Secure Messaging**: Generate signing keys for end-to-end encrypted communication
|
|
103
|
+
- **Blockchain Applications**: Create wallet-like accounts from mnemonic phrases
|
|
104
|
+
- **Majikah Ecosystem**: Use across all Majikah products and services
|
|
105
|
+
|
|
106
|
+
---
|
|
107
|
+
|
|
108
|
+
## Features
|
|
109
|
+
|
|
110
|
+
### Security First
|
|
111
|
+
- **Encrypted at Rest**: Private keys are encrypted with PBKDF2-derived keys (200,000 iterations)
|
|
112
|
+
- **AES-GCM Encryption**: Industry-standard authenticated encryption
|
|
113
|
+
- **Locked/Unlocked States**: Private keys only exist in memory when explicitly unlocked
|
|
114
|
+
- **Per-Identity Salts**: Each account uses a unique salt for encryption
|
|
115
|
+
|
|
116
|
+
### BIP39 Compliance
|
|
117
|
+
- **Standard Mnemonic Generation**: Generate 12 or 24-word seed phrases
|
|
118
|
+
- **Mnemonic Validation**: Built-in BIP39 validation
|
|
119
|
+
- **Deterministic Key Derivation**: Same mnemonic always produces the same keys
|
|
120
|
+
|
|
121
|
+
### Developer Friendly
|
|
122
|
+
- **TypeScript Support**: Full type definitions included
|
|
123
|
+
- **Simple API**: Intuitive CRUD operations
|
|
124
|
+
- **Error Handling**: Comprehensive error messages with `MajikKeyError`
|
|
125
|
+
- **Method Chaining**: Fluent API for common operations
|
|
126
|
+
|
|
127
|
+
### Import/Export
|
|
128
|
+
- **JSON Serialization**: Safe storage format (no private keys exposed)
|
|
129
|
+
- **Mnemonic Backup**: Export/import encrypted backups using mnemonic phrases
|
|
130
|
+
- **MnemonicJSON Format**: Compatible format for seed phrase storage
|
|
131
|
+
|
|
132
|
+
### Interoperability
|
|
133
|
+
- **Majik Message Compatible**: Seamlessly import/export to Majik Message
|
|
134
|
+
- **Majik Contact Integration**: Convert keys to contact format
|
|
135
|
+
- **Majikah Ecosystem**: Works across all Majikah products
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Installation
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Using npm
|
|
143
|
+
npm install @majikah/majik-key
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Quick Start
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
153
|
+
|
|
154
|
+
// Generate a new mnemonic
|
|
155
|
+
const mnemonic = MajikKey.generateMnemonic(); // 12 words
|
|
156
|
+
console.log('Save this mnemonic:', mnemonic);
|
|
157
|
+
|
|
158
|
+
// Create a new Majik Key (unlocked state)
|
|
159
|
+
const key = await MajikKey.create(
|
|
160
|
+
mnemonic,
|
|
161
|
+
'my-secure-passphrase',
|
|
162
|
+
'My First Key'
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
console.log('Key ID:', key.id);
|
|
166
|
+
console.log('Fingerprint:', key.fingerprint);
|
|
167
|
+
console.log('Is Unlocked:', key.isUnlocked); // true
|
|
168
|
+
|
|
169
|
+
// Lock the key (clear private keys from memory)
|
|
170
|
+
key.lock();
|
|
171
|
+
console.log('Is Locked:', key.isLocked); // true
|
|
172
|
+
|
|
173
|
+
// Unlock when needed
|
|
174
|
+
await key.unlock('my-secure-passphrase');
|
|
175
|
+
console.log('Is Unlocked:', key.isUnlocked); // true
|
|
176
|
+
|
|
177
|
+
// Access private key (only when unlocked)
|
|
178
|
+
const privateKey = key.getPrivateKey();
|
|
179
|
+
const privateKeyBase64 = key.getPrivateKeyBase64();
|
|
180
|
+
|
|
181
|
+
// Save to storage (private keys never included)
|
|
182
|
+
const json = key.toJSON();
|
|
183
|
+
localStorage.setItem('myKey', JSON.stringify(json));
|
|
184
|
+
|
|
185
|
+
// Load from storage (locked state)
|
|
186
|
+
const loadedKey = MajikKey.fromJSON(json);
|
|
187
|
+
await loadedKey.unlock('my-secure-passphrase');
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
## API Reference
|
|
193
|
+
|
|
194
|
+
### Static Methods
|
|
195
|
+
|
|
196
|
+
#### `MajikKey.create(mnemonic, passphrase, label?)`
|
|
197
|
+
Create a new Majik Key from a mnemonic phrase.
|
|
198
|
+
|
|
199
|
+
**Parameters:**
|
|
200
|
+
- `mnemonic: string` - BIP39 mnemonic phrase (12-24 words)
|
|
201
|
+
- `passphrase: string` - Passphrase to encrypt the private key at rest
|
|
202
|
+
- `label?: string` - Optional label for the key
|
|
203
|
+
|
|
204
|
+
**Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
|
|
205
|
+
|
|
206
|
+
**Example:**
|
|
207
|
+
```ts
|
|
208
|
+
const mnemonic = 'witch collapse practice feed shame open despair creek road again ice least';
|
|
209
|
+
const key = await MajikKey.create(mnemonic, 'my-password', 'Personal Account');
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
#### `MajikKey.fromJSON(json)`
|
|
216
|
+
Load a Majik Key from JSON (locked state).
|
|
217
|
+
|
|
218
|
+
**Parameters:**
|
|
219
|
+
- `json: MajikKeyJSON | string` - JSON object or string
|
|
220
|
+
|
|
221
|
+
**Returns:** `MajikKey` - A locked MajikKey instance
|
|
222
|
+
|
|
223
|
+
**Example:**
|
|
224
|
+
```ts
|
|
225
|
+
const json = localStorage.getItem('myKey');
|
|
226
|
+
const key = MajikKey.fromJSON(json);
|
|
227
|
+
await key.unlock('my-password');
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
#### `MajikKey.fromMnemonicJSON(mnemonicJson, passphrase, label?)`
|
|
233
|
+
Create a Majik Key from MnemonicJSON format.
|
|
234
|
+
|
|
235
|
+
**Parameters:**
|
|
236
|
+
- `mnemonicJson: MnemonicJSON | string` - MnemonicJSON object or string
|
|
237
|
+
- `passphrase: string` - Passphrase to encrypt the key at rest
|
|
238
|
+
- `label?: string` - Optional label for the key
|
|
239
|
+
|
|
240
|
+
**Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
|
|
241
|
+
|
|
242
|
+
**Example:**
|
|
243
|
+
```ts
|
|
244
|
+
const mnemonicData = {
|
|
245
|
+
id: 'backup-id',
|
|
246
|
+
seed: ['word1', 'word2', ...],
|
|
247
|
+
phrase: 'optional-encryption-phrase'
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
const key = await MajikKey.fromMnemonicJSON(mnemonicData, 'my-password');
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
---
|
|
254
|
+
|
|
255
|
+
#### `MajikKey.importFromMnemonicBackup(backup, mnemonic, passphrase, label?)`
|
|
256
|
+
Import a Majik Key from a mnemonic-encrypted backup.
|
|
257
|
+
|
|
258
|
+
**Parameters:**
|
|
259
|
+
- `backup: string` - Base64-encoded backup string
|
|
260
|
+
- `mnemonic: string` - The mnemonic phrase used to encrypt the backup
|
|
261
|
+
- `passphrase: string` - Passphrase to encrypt the imported key
|
|
262
|
+
- `label?: string` - Optional label for the key
|
|
263
|
+
|
|
264
|
+
**Returns:** `Promise<MajikKey>` - A new unlocked MajikKey instance
|
|
265
|
+
|
|
266
|
+
**Example:**
|
|
267
|
+
```ts
|
|
268
|
+
const backupString = 'eT8xY2F...'; // From exportMnemonicBackup()
|
|
269
|
+
const key = await MajikKey.importFromMnemonicBackup(
|
|
270
|
+
backupString,
|
|
271
|
+
mnemonic,
|
|
272
|
+
'new-password',
|
|
273
|
+
'Restored Account'
|
|
274
|
+
);
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
#### `MajikKey.generateMnemonic(strength?)`
|
|
280
|
+
Generate a new BIP39 mnemonic phrase.
|
|
281
|
+
|
|
282
|
+
**Parameters:**
|
|
283
|
+
- `strength?: 128 | 256` - Entropy strength (128 = 12 words, 256 = 24 words). Default: 128
|
|
284
|
+
|
|
285
|
+
**Returns:** `string` - A new mnemonic phrase
|
|
286
|
+
|
|
287
|
+
**Example:**
|
|
288
|
+
```ts
|
|
289
|
+
const mnemonic12 = MajikKey.generateMnemonic(); // 12 words
|
|
290
|
+
const mnemonic24 = MajikKey.generateMnemonic(256); // 24 words
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
---
|
|
294
|
+
|
|
295
|
+
#### `MajikKey.validateMnemonic(mnemonic)`
|
|
296
|
+
Validate a BIP39 mnemonic phrase.
|
|
297
|
+
|
|
298
|
+
**Parameters:**
|
|
299
|
+
- `mnemonic: string` - Mnemonic phrase to validate
|
|
300
|
+
|
|
301
|
+
**Returns:** `boolean` - true if valid, false otherwise
|
|
302
|
+
|
|
303
|
+
**Example:**
|
|
304
|
+
```ts
|
|
305
|
+
const isValid = MajikKey.validateMnemonic('witch collapse practice...');
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
### Instance Methods
|
|
311
|
+
|
|
312
|
+
#### `unlock(passphrase)`
|
|
313
|
+
Unlock the Majik Key by decrypting the private key.
|
|
314
|
+
|
|
315
|
+
**Parameters:**
|
|
316
|
+
- `passphrase: string` - Passphrase to decrypt the private key
|
|
317
|
+
|
|
318
|
+
**Returns:** `Promise<this>` - This instance for chaining
|
|
319
|
+
|
|
320
|
+
**Throws:** `MajikKeyError` if passphrase is incorrect or key is already unlocked
|
|
321
|
+
|
|
322
|
+
**Example:**
|
|
323
|
+
```ts
|
|
324
|
+
await key.unlock('my-password');
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
#### `lock()`
|
|
330
|
+
Lock the Majik Key by clearing private keys from memory.
|
|
331
|
+
|
|
332
|
+
**Returns:** `this` - This instance for chaining
|
|
333
|
+
|
|
334
|
+
**Example:**
|
|
335
|
+
```ts
|
|
336
|
+
key.lock();
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
#### `verify(passphrase)`
|
|
342
|
+
Verify that a passphrase can decrypt the private key.
|
|
343
|
+
|
|
344
|
+
**Parameters:**
|
|
345
|
+
- `passphrase: string` - Passphrase to verify
|
|
346
|
+
|
|
347
|
+
**Returns:** `Promise<boolean>` - true if valid, false otherwise
|
|
348
|
+
|
|
349
|
+
**Example:**
|
|
350
|
+
```ts
|
|
351
|
+
const isValid = await key.verify('my-password');
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
---
|
|
355
|
+
|
|
356
|
+
#### `updateLabel(newLabel)`
|
|
357
|
+
Update the label of the Majik Key.
|
|
358
|
+
|
|
359
|
+
**Parameters:**
|
|
360
|
+
- `newLabel: string` - New label value
|
|
361
|
+
|
|
362
|
+
**Returns:** `this` - This instance for chaining
|
|
363
|
+
|
|
364
|
+
**Example:**
|
|
365
|
+
```ts
|
|
366
|
+
key.updateLabel('Work Account');
|
|
367
|
+
```
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
#### `updatePassphrase(currentPassphrase, newPassphrase)`
|
|
372
|
+
Change the passphrase used to encrypt the private key.
|
|
373
|
+
|
|
374
|
+
**Parameters:**
|
|
375
|
+
- `currentPassphrase: string` - Current passphrase
|
|
376
|
+
- `newPassphrase: string` - New passphrase
|
|
377
|
+
|
|
378
|
+
**Returns:** `Promise<this>` - This instance for chaining
|
|
379
|
+
|
|
380
|
+
**Throws:** `MajikKeyError` if current passphrase is incorrect
|
|
381
|
+
|
|
382
|
+
**Example:**
|
|
383
|
+
```ts
|
|
384
|
+
await key.updatePassphrase('old-password', 'new-password');
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
#### `getPrivateKey()`
|
|
390
|
+
Get the private key (only when unlocked).
|
|
391
|
+
|
|
392
|
+
**Returns:** `CryptoKey | { raw: Uint8Array }` - The private key
|
|
393
|
+
|
|
394
|
+
**Throws:** `MajikKeyError` if the key is locked
|
|
395
|
+
|
|
396
|
+
**Example:**
|
|
397
|
+
```ts
|
|
398
|
+
const privateKey = key.getPrivateKey();
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
#### `getPrivateKeyBase64()`
|
|
404
|
+
Get the private key as base64 (only when unlocked).
|
|
405
|
+
|
|
406
|
+
**Returns:** `string` - The private key in base64 format
|
|
407
|
+
|
|
408
|
+
**Throws:** `MajikKeyError` if the key is locked
|
|
409
|
+
|
|
410
|
+
**Example:**
|
|
411
|
+
```ts
|
|
412
|
+
const privateKeyBase64 = key.getPrivateKeyBase64();
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
#### `toJSON()`
|
|
418
|
+
Export to JSON format (safe for storage).
|
|
419
|
+
|
|
420
|
+
**Returns:** `MajikKeyJSON` - JSON representation (private keys never included)
|
|
421
|
+
|
|
422
|
+
**Example:**
|
|
423
|
+
```ts
|
|
424
|
+
const json = key.toJSON();
|
|
425
|
+
localStorage.setItem('myKey', JSON.stringify(json));
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
---
|
|
429
|
+
|
|
430
|
+
#### `toString(pretty?)`
|
|
431
|
+
Export to JSON string.
|
|
432
|
+
|
|
433
|
+
**Parameters:**
|
|
434
|
+
- `pretty?: boolean` - Whether to pretty-print. Default: false
|
|
435
|
+
|
|
436
|
+
**Returns:** `string` - JSON string representation
|
|
437
|
+
|
|
438
|
+
**Example:**
|
|
439
|
+
```ts
|
|
440
|
+
const jsonString = key.toString(true);
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
#### `toMnemonicJSON(mnemonic, passphrase?)`
|
|
446
|
+
Export to MnemonicJSON format.
|
|
447
|
+
|
|
448
|
+
**Parameters:**
|
|
449
|
+
- `mnemonic: string` - The BIP39 mnemonic phrase
|
|
450
|
+
- `passphrase?: string` - Optional passphrase
|
|
451
|
+
|
|
452
|
+
**Returns:** `MnemonicJSON` - MnemonicJSON object
|
|
453
|
+
|
|
454
|
+
**Throws:** `MajikKeyError` if the key is locked
|
|
455
|
+
|
|
456
|
+
**Example:**
|
|
457
|
+
```ts
|
|
458
|
+
const mnemonicData = key.toMnemonicJSON(mnemonic, 'encryption-phrase');
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
---
|
|
462
|
+
|
|
463
|
+
#### `exportMnemonicBackup(mnemonic)`
|
|
464
|
+
Export a mnemonic-encrypted backup.
|
|
465
|
+
|
|
466
|
+
**Parameters:**
|
|
467
|
+
- `mnemonic: string` - The original mnemonic phrase
|
|
468
|
+
|
|
469
|
+
**Returns:** `Promise<string>` - Base64-encoded backup string
|
|
470
|
+
|
|
471
|
+
**Throws:** `MajikKeyError` if the key is locked
|
|
472
|
+
|
|
473
|
+
**Example:**
|
|
474
|
+
```ts
|
|
475
|
+
const backup = await key.exportMnemonicBackup(mnemonic);
|
|
476
|
+
```
|
|
477
|
+
|
|
478
|
+
---
|
|
479
|
+
|
|
480
|
+
#### `toContact()`
|
|
481
|
+
Create a MajikContact from this Majik Key.
|
|
482
|
+
|
|
483
|
+
**Returns:** `MajikContact` - A MajikContact instance
|
|
484
|
+
|
|
485
|
+
**Example:**
|
|
486
|
+
```ts
|
|
487
|
+
const contact = key.toContact();
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
---
|
|
491
|
+
|
|
492
|
+
#### `toMajikMessageIdentity(user, options?)`
|
|
493
|
+
Convert to MajikMessageIdentity for use in Majik Message.
|
|
494
|
+
|
|
495
|
+
**Parameters:**
|
|
496
|
+
- `user: MajikUser` - MajikUser instance
|
|
497
|
+
- `options?: { label?: string, restricted?: boolean }` - Optional configuration
|
|
498
|
+
|
|
499
|
+
**Returns:** `Promise<MajikMessageIdentity>` - MajikMessageIdentity instance
|
|
500
|
+
|
|
501
|
+
**Example:**
|
|
502
|
+
```ts
|
|
503
|
+
const identity = await key.toMajikMessageIdentity(user, {
|
|
504
|
+
label: 'My Account',
|
|
505
|
+
restricted: false
|
|
506
|
+
});
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
---
|
|
510
|
+
|
|
511
|
+
### Getters
|
|
512
|
+
|
|
513
|
+
#### `id: string`
|
|
514
|
+
The unique identifier (fingerprint).
|
|
515
|
+
|
|
516
|
+
#### `fingerprint: string`
|
|
517
|
+
The cryptographic fingerprint.
|
|
518
|
+
|
|
519
|
+
#### `publicKey: CryptoKey | { raw: Uint8Array }`
|
|
520
|
+
The public key.
|
|
521
|
+
|
|
522
|
+
#### `publicKeyBase64: string`
|
|
523
|
+
The public key in base64 format.
|
|
524
|
+
|
|
525
|
+
#### `label: string`
|
|
526
|
+
The user-defined label.
|
|
527
|
+
|
|
528
|
+
#### `backup: string`
|
|
529
|
+
The mnemonic backup identifier.
|
|
530
|
+
|
|
531
|
+
#### `timestamp: Date`
|
|
532
|
+
The creation timestamp.
|
|
533
|
+
|
|
534
|
+
#### `isLocked: boolean`
|
|
535
|
+
Whether the key is currently locked.
|
|
536
|
+
|
|
537
|
+
#### `isUnlocked: boolean`
|
|
538
|
+
Whether the key is currently unlocked.
|
|
539
|
+
|
|
540
|
+
#### `metadata: MajikKeyMetadata`
|
|
541
|
+
Safe metadata object (no sensitive data).
|
|
542
|
+
|
|
543
|
+
**Example:**
|
|
544
|
+
```ts
|
|
545
|
+
console.log(key.metadata);
|
|
546
|
+
// {
|
|
547
|
+
// id: 'fingerprint-id',
|
|
548
|
+
// fingerprint: 'fingerprint-id',
|
|
549
|
+
// label: 'My Key',
|
|
550
|
+
// timestamp: Date,
|
|
551
|
+
// isLocked: false
|
|
552
|
+
// }
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
---
|
|
556
|
+
|
|
557
|
+
## Usage Examples
|
|
558
|
+
|
|
559
|
+
### Example 1: Create and Manage a Key
|
|
560
|
+
|
|
561
|
+
```ts
|
|
562
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
563
|
+
|
|
564
|
+
async function createKey() {
|
|
565
|
+
// Generate mnemonic
|
|
566
|
+
const mnemonic = MajikKey.generateMnemonic();
|
|
567
|
+
console.log('🔑 Save this mnemonic safely:', mnemonic);
|
|
568
|
+
|
|
569
|
+
// Create key
|
|
570
|
+
const key = await MajikKey.create(
|
|
571
|
+
mnemonic,
|
|
572
|
+
'secure-passphrase',
|
|
573
|
+
'Personal Account'
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
console.log('✅ Key created!');
|
|
577
|
+
console.log('ID:', key.id);
|
|
578
|
+
console.log('Fingerprint:', key.fingerprint);
|
|
579
|
+
console.log('Label:', key.label);
|
|
580
|
+
|
|
581
|
+
// Save to storage
|
|
582
|
+
const json = key.toJSON();
|
|
583
|
+
localStorage.setItem('myKey', JSON.stringify(json));
|
|
584
|
+
|
|
585
|
+
return { key, mnemonic };
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
createKey();
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
---
|
|
592
|
+
|
|
593
|
+
### Example 2: Lock/Unlock Pattern
|
|
594
|
+
|
|
595
|
+
```ts
|
|
596
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
597
|
+
|
|
598
|
+
async function secureLockPattern() {
|
|
599
|
+
const json = localStorage.getItem('myKey');
|
|
600
|
+
const key = MajikKey.fromJSON(json);
|
|
601
|
+
|
|
602
|
+
// Key is locked by default when loaded from JSON
|
|
603
|
+
console.log('Locked:', key.isLocked); // true
|
|
604
|
+
|
|
605
|
+
try {
|
|
606
|
+
// This will throw an error
|
|
607
|
+
const privateKey = key.getPrivateKey();
|
|
608
|
+
} catch (error) {
|
|
609
|
+
console.log('❌ Cannot access private key when locked');
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// Unlock to use private key
|
|
613
|
+
await key.unlock('secure-passphrase');
|
|
614
|
+
console.log('Unlocked:', key.isUnlocked); // true
|
|
615
|
+
|
|
616
|
+
// Now we can access private keys
|
|
617
|
+
const privateKey = key.getPrivateKey();
|
|
618
|
+
const privateKeyBase64 = key.getPrivateKeyBase64();
|
|
619
|
+
|
|
620
|
+
// Use the key for cryptographic operations
|
|
621
|
+
// ...
|
|
622
|
+
|
|
623
|
+
// Lock again when done
|
|
624
|
+
key.lock();
|
|
625
|
+
console.log('🔒 Key locked again');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
secureLockPattern();
|
|
629
|
+
```
|
|
630
|
+
|
|
631
|
+
---
|
|
632
|
+
|
|
633
|
+
### Example 3: Backup and Recovery
|
|
634
|
+
|
|
635
|
+
```ts
|
|
636
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
637
|
+
|
|
638
|
+
async function backupAndRecover() {
|
|
639
|
+
const mnemonic = MajikKey.generateMnemonic();
|
|
640
|
+
const key = await MajikKey.create(mnemonic, 'password123', 'Original Key');
|
|
641
|
+
|
|
642
|
+
//Download as Blob JSON File
|
|
643
|
+
|
|
644
|
+
const jsonData = await key.toMnemonicJSON(mnemonic, 'password123');
|
|
645
|
+
const jsonString = JSON.stringify(jsonData);
|
|
646
|
+
const blob = new Blob([jsonString], {
|
|
647
|
+
type: "application/json;charset=utf-8",
|
|
648
|
+
});
|
|
649
|
+
downloadBlob(
|
|
650
|
+
blob,
|
|
651
|
+
"json",
|
|
652
|
+
`${label} | ${key.id} | SEED KEY`,
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
// Later... recover from backup
|
|
658
|
+
|
|
659
|
+
//Parse the downloaded JSON into this object
|
|
660
|
+
const jsonData: MnemonicJSON = {
|
|
661
|
+
id: "abc123",
|
|
662
|
+
seed: ["word1", "word2", ...],
|
|
663
|
+
phrase: 'password123',
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
const recoveredKey = await MajikKey.importFromMnemonicBackup(
|
|
667
|
+
jsonData.id,
|
|
668
|
+
seedArrayToString(jsonData.seed),
|
|
669
|
+
jsonData.phrase,
|
|
670
|
+
'Recovered Key'
|
|
671
|
+
);
|
|
672
|
+
|
|
673
|
+
console.log('✅ Key recovered!');
|
|
674
|
+
console.log('Same fingerprint:', key.fingerprint === recoveredKey.fingerprint);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
backupAndRecover();
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
|
|
681
|
+
---
|
|
682
|
+
|
|
683
|
+
### Example 4: Update Passphrase
|
|
684
|
+
|
|
685
|
+
```ts
|
|
686
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
687
|
+
|
|
688
|
+
async function changePassphrase() {
|
|
689
|
+
const json = localStorage.getItem('myKey');
|
|
690
|
+
const key = MajikKey.fromJSON(json);
|
|
691
|
+
|
|
692
|
+
// Must unlock first
|
|
693
|
+
await key.unlock('old-password');
|
|
694
|
+
|
|
695
|
+
// Change passphrase
|
|
696
|
+
await key.updatePassphrase('old-password', 'new-secure-password');
|
|
697
|
+
console.log('✅ Passphrase updated!');
|
|
698
|
+
|
|
699
|
+
// Save updated key
|
|
700
|
+
localStorage.setItem('myKey', JSON.stringify(key.toJSON()));
|
|
701
|
+
|
|
702
|
+
// Verify new passphrase works
|
|
703
|
+
key.lock();
|
|
704
|
+
await key.unlock('new-secure-password');
|
|
705
|
+
console.log('✅ New passphrase verified!');
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
changePassphrase();
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
### Example 5: Verify Passphrase
|
|
714
|
+
|
|
715
|
+
```ts
|
|
716
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
717
|
+
|
|
718
|
+
async function verifyPassphrase() {
|
|
719
|
+
const json = localStorage.getItem('myKey');
|
|
720
|
+
const key = MajikKey.fromJSON(json);
|
|
721
|
+
|
|
722
|
+
// Verify without unlocking
|
|
723
|
+
const isValid = await key.verify('user-entered-password');
|
|
724
|
+
|
|
725
|
+
if (isValid) {
|
|
726
|
+
console.log('✅ Passphrase is correct');
|
|
727
|
+
await key.unlock('user-entered-password');
|
|
728
|
+
// Proceed with operations...
|
|
729
|
+
} else {
|
|
730
|
+
console.log('❌ Invalid passphrase');
|
|
731
|
+
// Show error to user
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
verifyPassphrase();
|
|
736
|
+
```
|
|
737
|
+
|
|
738
|
+
---
|
|
739
|
+
|
|
740
|
+
## Integration with Majik Message
|
|
741
|
+
|
|
742
|
+
Majik Key is fully compatible with **Majik Message** as its seed phrase account implementation. Keys created with Majik Key can be directly imported into Majik Message.
|
|
743
|
+
|
|
744
|
+
### Importing to Majik Message
|
|
745
|
+
|
|
746
|
+
```ts
|
|
747
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
748
|
+
|
|
749
|
+
async function importToMajikMessage() {
|
|
750
|
+
// Create or load a Majik Key
|
|
751
|
+
const mnemonic = MajikKey.generateMnemonic();
|
|
752
|
+
const key = await MajikKey.create(mnemonic, 'password', 'Message Account');
|
|
753
|
+
|
|
754
|
+
// Export to MnemonicJSON format for Majik Message
|
|
755
|
+
const mnemonicData = key.toMnemonicJSON(mnemonic, 'password');
|
|
756
|
+
const jsonString = JSON.stringify(mnemonicData);
|
|
757
|
+
|
|
758
|
+
// Download this blob as a JSON locally
|
|
759
|
+
const blob = new Blob([jsonString], {
|
|
760
|
+
type: "application/json;charset=utf-8",
|
|
761
|
+
});
|
|
762
|
+
|
|
763
|
+
// This mnemonicData can be imported directly into Majik Message
|
|
764
|
+
// as a seed phrase account
|
|
765
|
+
console.log('Import the saved JSON to Majik Message:', mnemonicData);
|
|
766
|
+
}
|
|
767
|
+
```
|
|
768
|
+
|
|
769
|
+
### Converting to Majik Message Identity
|
|
770
|
+
|
|
771
|
+
```ts
|
|
772
|
+
import { MajikKey } from '@majikah/majik-key';
|
|
773
|
+
import { MajikUser } from '@thezelijah/majik-user';
|
|
774
|
+
|
|
775
|
+
async function createMessageIdentity() {
|
|
776
|
+
const mnemonic = MajikKey.generateMnemonic();
|
|
777
|
+
const key = await MajikKey.create(mnemonic, 'password', 'Message Identity');
|
|
778
|
+
|
|
779
|
+
// Create/parse a MajikUser instance
|
|
780
|
+
const user = new MajikUser({
|
|
781
|
+
username: 'myusername',
|
|
782
|
+
// ... other user properties
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
// Convert to Majik Message Identity
|
|
786
|
+
const identity = await key.toMajikMessageIdentity(user, {
|
|
787
|
+
label: 'My Message Account',
|
|
788
|
+
restricted: false
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
console.log('Majik Message Identity created:', identity);
|
|
792
|
+
}
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
## Security Considerations
|
|
798
|
+
|
|
799
|
+
### Best Practices
|
|
800
|
+
|
|
801
|
+
1. **Never expose mnemonics**: Treat mnemonic phrases like passwords. Never log, transmit, or store them unencrypted.
|
|
802
|
+
|
|
803
|
+
2. **Use strong passphrases**: Choose passphrases with high entropy (mix of letters, numbers, symbols).
|
|
804
|
+
|
|
805
|
+
3. **Lock when not in use**: Always lock keys when private key access is not needed.
|
|
806
|
+
|
|
807
|
+
4. **Secure storage**: Store JSON exports in secure locations (encrypted databases, secure storage APIs).
|
|
808
|
+
|
|
809
|
+
5. **Backup mnemonics**: Store mnemonic phrases in multiple secure locations (password manager, paper backup, hardware wallet).
|
|
810
|
+
|
|
811
|
+
### Security Features
|
|
812
|
+
|
|
813
|
+
- **PBKDF2 Key Derivation**: 200,000 iterations with SHA-256
|
|
814
|
+
- **AES-GCM Encryption**: Authenticated encryption with random IVs
|
|
815
|
+
- **Per-Identity Salts**: Unique salt for each key prevents rainbow table attacks
|
|
816
|
+
- **No Private Key Exposure**: Private keys never included in JSON exports
|
|
817
|
+
- **Memory Management**: Private keys cleared from memory when locked
|
|
818
|
+
|
|
819
|
+
### What NOT to Do
|
|
820
|
+
|
|
821
|
+
❌ **DON'T** store mnemonics in code or version control
|
|
822
|
+
❌ **DON'T** transmit mnemonics over insecure channels
|
|
823
|
+
❌ **DON'T** use weak passphrases like "password123"
|
|
824
|
+
❌ **DON'T** share mnemonics or passphrases with anyone
|
|
825
|
+
❌ **DON'T** screenshot or photograph mnemonics
|
|
826
|
+
|
|
827
|
+
### What TO Do
|
|
828
|
+
|
|
829
|
+
✅ **DO** use password managers for mnemonic storage
|
|
830
|
+
✅ **DO** write mnemonics on paper and store securely
|
|
831
|
+
✅ **DO** use hardware security modules when possible
|
|
832
|
+
✅ **DO** test recovery procedures before relying on them
|
|
833
|
+
✅ **DO** keep multiple encrypted backups in different locations
|
|
834
|
+
|
|
835
|
+
---
|
|
836
|
+
|
|
837
|
+
### Tips & Reminders
|
|
838
|
+
|
|
839
|
+
#### For Developers
|
|
840
|
+
|
|
841
|
+
- **Remember**: Always validate user input before creating or unlocking keys.
|
|
842
|
+
|
|
843
|
+
- **Security**: Never log sensitive data (mnemonics, private keys, passphrases) in production.
|
|
844
|
+
|
|
845
|
+
- **Performance**: Lock keys when not in use to free memory and reduce attack surface.
|
|
846
|
+
|
|
847
|
+
- **Testing**: Test backup/recovery procedures in development before deploying to production.
|
|
848
|
+
|
|
849
|
+
- **Dependencies**: Keep `@scure/bip39` and other crypto dependencies up to date.
|
|
850
|
+
|
|
851
|
+
#### For Users
|
|
852
|
+
|
|
853
|
+
- **Backup**: Always keep multiple backups of your mnemonic phrase in secure locations.
|
|
854
|
+
|
|
855
|
+
- **Passphrase**: Use a strong, unique passphrase for each Majik Key.
|
|
856
|
+
|
|
857
|
+
- **Recovery**: Test your ability to recover keys from backups before you need to.
|
|
858
|
+
|
|
859
|
+
- **Organization**: Use meaningful labels to identify different keys.
|
|
860
|
+
- **Loss Prevention**: Losing your mnemonic phrase means permanent loss of access to your key.
|
|
861
|
+
|
|
862
|
+
---
|
|
863
|
+
|
|
864
|
+
## Related Projects
|
|
865
|
+
|
|
866
|
+
### [Majik Message](https://message.majikah.solutions)
|
|
867
|
+
Secure messaging platform using Majik Keys
|
|
868
|
+
|
|
869
|
+
[Read more about Majik Message here](https://majikah.solutions/products/majik-message)
|
|
870
|
+
|
|
871
|
+
[](https://message.majikah.solutions)
|
|
872
|
+
|
|
873
|
+
> Click the image to try Majik Message live.
|
|
874
|
+
|
|
875
|
+
[Read Docs](https://majikah.solutions/products/majik-message/docs)
|
|
876
|
+
|
|
877
|
+
|
|
878
|
+
Also available on [Microsoft Store](https://apps.microsoft.com/detail/9pmjgvzzjspn) for free.
|
|
879
|
+
|
|
880
|
+
[Official Repository](https://github.com/Majikah/majik-message)
|
|
881
|
+
[SDK Library](https://www.npmjs.com/package/@majikah/majik-message)
|
|
882
|
+
|
|
883
|
+
---
|
|
884
|
+
|
|
885
|
+
## Contributing
|
|
886
|
+
|
|
887
|
+
If you want to contribute or help extend support to more platforms, reach out via email. All contributions are welcome!
|
|
888
|
+
|
|
889
|
+
---
|
|
890
|
+
|
|
891
|
+
## License
|
|
892
|
+
|
|
893
|
+
[Apache-2.0](LICENSE) — free for personal and commercial use.
|
|
894
|
+
|
|
895
|
+
---
|
|
896
|
+
## Author
|
|
897
|
+
|
|
898
|
+
Made with 💙 by [@thezelijah](https://github.com/jedlsf)
|
|
899
|
+
|
|
900
|
+
## About the Developer
|
|
901
|
+
|
|
902
|
+
- **Developer**: Josef Elijah Fabian
|
|
903
|
+
- **GitHub**: [https://github.com/jedlsf](https://github.com/jedlsf)
|
|
904
|
+
- **Project Repository**: [https://github.com/jedlsf/majik-key](https://github.com/jedlsf/majik-key)
|
|
905
|
+
|
|
906
|
+
---
|
|
907
|
+
|
|
908
|
+
## Contact
|
|
909
|
+
|
|
910
|
+
- **Business Email**: [business@thezelijah.world](mailto:business@thezelijah.world)
|
|
911
|
+
- **Official Website**: [https://www.thezelijah.world](https://www.thezelijah.world)
|