mirror of https://github.com/status-im/bip39.git
Allow excluding wordlists when building for browserify
This commit is contained in:
parent
6dedef08d4
commit
c30b47b63d
56
README.md
56
README.md
|
@ -16,6 +16,62 @@ When a checksum is invalid, warn the user that the phrase is not something gener
|
|||
|
||||
However, there should be other checks in place, such as checking to make sure the user is inputting 12 words or more separated by a space. ie. `phrase.trim().split(/\s+/g).length >= 12`
|
||||
|
||||
## Removing wordlists from webpack/browserify
|
||||
|
||||
Browserify/Webpack bundles can get very large if you include all the wordlists, so you can now exclude wordlists to make your bundle lighter.
|
||||
|
||||
For example, if we want to exclude all wordlists besides chinese_simplified, you could build using the browserify command below.
|
||||
|
||||
```bash
|
||||
$ browserify -r bip39 -s bip39 \
|
||||
--exclude=./wordlists/english.json \
|
||||
--exclude=./wordlists/japanese.json \
|
||||
--exclude=./wordlists/spanish.json \
|
||||
--exclude=./wordlists/italian.json \
|
||||
--exclude=./wordlists/french.json \
|
||||
--exclude=./wordlists/korean.json \
|
||||
--exclude=./wordlists/chinese_traditional.json \
|
||||
> bip39.browser.js
|
||||
```
|
||||
|
||||
This will create a bundle that only contains the chinese_simplified wordlist, and it will be the default wordlist for all calls without explicit wordlists.
|
||||
|
||||
This is how it will look in the browser console.
|
||||
|
||||
```javascript
|
||||
> bip39.entropyToMnemonic('00000000000000000000000000000000')
|
||||
"的 的 的 的 的 的 的 的 的 的 的 在"
|
||||
> bip39.wordlists.chinese_simplified
|
||||
Array(2048) [ "的", "一", "是", "在", "不", "了", "有", "和", "人", "这", … ]
|
||||
> bip39.wordlists.english
|
||||
undefined
|
||||
> bip39.wordlists.japanese
|
||||
undefined
|
||||
> bip39.wordlists.spanish
|
||||
undefined
|
||||
> bip39.wordlists.italian
|
||||
undefined
|
||||
> bip39.wordlists.french
|
||||
undefined
|
||||
> bip39.wordlists.korean
|
||||
undefined
|
||||
> bip39.wordlists.chinese_traditional
|
||||
undefined
|
||||
```
|
||||
|
||||
For a list of supported wordlists check the wordlists folder. The name of the json file (minus the extension) is the name of the key to access the wordlist.
|
||||
|
||||
You can also change the default wordlist at runtime if you dislike the wordlist you were given as default.
|
||||
|
||||
```javascript
|
||||
> bip39.entropyToMnemonic('00000000000000000000000000000fff')
|
||||
"あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あいこくしん あまい ろんり"
|
||||
> bip39.setDefaultWordlist('italian')
|
||||
undefined
|
||||
> bip39.entropyToMnemonic('00000000000000000000000000000fff')
|
||||
"abaco abaco abaco abaco abaco abaco abaco abaco abaco abaco aforisma zibetto"
|
||||
```
|
||||
|
||||
## Installation
|
||||
``` bash
|
||||
npm install bip39
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
// browserify by default only pulls in files that are hard coded in requires
|
||||
// In order of last to first in this file, the default wordlist will be chosen
|
||||
// based on what is present. (Bundles may remove wordlists they don't need)
|
||||
const wordlists = {};
|
||||
exports.wordlists = wordlists;
|
||||
let _default;
|
||||
exports._default = _default;
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/chinese_simplified.json');
|
||||
wordlists.chinese_simplified = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/chinese_traditional.json');
|
||||
wordlists.chinese_traditional = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/korean.json');
|
||||
wordlists.korean = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/french.json');
|
||||
wordlists.french = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/italian.json');
|
||||
wordlists.italian = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/spanish.json');
|
||||
wordlists.spanish = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/japanese.json');
|
||||
wordlists.japanese = _default;
|
||||
wordlists.JA = _default;
|
||||
}
|
||||
catch (err) { }
|
||||
try {
|
||||
exports._default = _default = require('./wordlists/english.json');
|
||||
wordlists.english = _default;
|
||||
wordlists.EN = _default;
|
||||
}
|
||||
catch (err) { }
|
41
src/index.js
41
src/index.js
|
@ -5,18 +5,13 @@ const pbkdf2_1 = require("pbkdf2");
|
|||
const randomBytes = require("randombytes");
|
||||
// use unorm until String.prototype.normalize gets better browser support
|
||||
const unorm = require("unorm");
|
||||
const CHINESE_SIMPLIFIED_WORDLIST = require("./wordlists/chinese_simplified.json");
|
||||
const CHINESE_TRADITIONAL_WORDLIST = require("./wordlists/chinese_traditional.json");
|
||||
const ENGLISH_WORDLIST = require("./wordlists/english.json");
|
||||
const FRENCH_WORDLIST = require("./wordlists/french.json");
|
||||
const ITALIAN_WORDLIST = require("./wordlists/italian.json");
|
||||
const JAPANESE_WORDLIST = require("./wordlists/japanese.json");
|
||||
const KOREAN_WORDLIST = require("./wordlists/korean.json");
|
||||
const SPANISH_WORDLIST = require("./wordlists/spanish.json");
|
||||
const DEFAULT_WORDLIST = ENGLISH_WORDLIST;
|
||||
const _wordlists_1 = require("./_wordlists");
|
||||
let DEFAULT_WORDLIST = _wordlists_1._default;
|
||||
const INVALID_MNEMONIC = 'Invalid mnemonic';
|
||||
const INVALID_ENTROPY = 'Invalid entropy';
|
||||
const INVALID_CHECKSUM = 'Invalid mnemonic checksum';
|
||||
const WORDLIST_REQUIRED = 'A wordlist is required but a default could not be found.\n' +
|
||||
'Please explicitly pass a 2048 word array explicitly.';
|
||||
function lpad(str, padString, length) {
|
||||
while (str.length < length)
|
||||
str = padString + str;
|
||||
|
@ -74,6 +69,9 @@ async function mnemonicToSeedHexAsync(mnemonic, password) {
|
|||
exports.mnemonicToSeedHexAsync = mnemonicToSeedHexAsync;
|
||||
function mnemonicToEntropy(mnemonic, wordlist) {
|
||||
wordlist = wordlist || DEFAULT_WORDLIST;
|
||||
if (!wordlist) {
|
||||
throw new Error(WORDLIST_REQUIRED);
|
||||
}
|
||||
const words = unorm.nfkd(mnemonic).split(' ');
|
||||
if (words.length % 3 !== 0)
|
||||
throw new Error(INVALID_MNEMONIC);
|
||||
|
@ -109,6 +107,9 @@ function entropyToMnemonic(entropy, wordlist) {
|
|||
if (!Buffer.isBuffer(entropy))
|
||||
entropy = Buffer.from(entropy, 'hex');
|
||||
wordlist = wordlist || DEFAULT_WORDLIST;
|
||||
if (!wordlist) {
|
||||
throw new Error(WORDLIST_REQUIRED);
|
||||
}
|
||||
// 128 <= ENT <= 256
|
||||
if (entropy.length < 16)
|
||||
throw new TypeError(INVALID_ENTROPY);
|
||||
|
@ -124,7 +125,7 @@ function entropyToMnemonic(entropy, wordlist) {
|
|||
const index = binaryToByte(binary);
|
||||
return wordlist[index];
|
||||
});
|
||||
return wordlist === JAPANESE_WORDLIST
|
||||
return wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093' // Japanese wordlist
|
||||
? words.join('\u3000')
|
||||
: words.join(' ');
|
||||
}
|
||||
|
@ -147,15 +148,11 @@ function validateMnemonic(mnemonic, wordlist) {
|
|||
return true;
|
||||
}
|
||||
exports.validateMnemonic = validateMnemonic;
|
||||
exports.wordlists = {
|
||||
EN: ENGLISH_WORDLIST,
|
||||
JA: JAPANESE_WORDLIST,
|
||||
chinese_simplified: CHINESE_SIMPLIFIED_WORDLIST,
|
||||
chinese_traditional: CHINESE_TRADITIONAL_WORDLIST,
|
||||
english: ENGLISH_WORDLIST,
|
||||
french: FRENCH_WORDLIST,
|
||||
italian: ITALIAN_WORDLIST,
|
||||
japanese: JAPANESE_WORDLIST,
|
||||
korean: KOREAN_WORDLIST,
|
||||
spanish: SPANISH_WORDLIST,
|
||||
};
|
||||
function setDefaultWordlist(language) {
|
||||
const result = _wordlists_1.wordlists[language];
|
||||
if (result)
|
||||
DEFAULT_WORDLIST = result;
|
||||
}
|
||||
exports.setDefaultWordlist = setDefaultWordlist;
|
||||
var _wordlists_2 = require("./_wordlists");
|
||||
exports.wordlists = _wordlists_2.wordlists;
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
// browserify by default only pulls in files that are hard coded in requires
|
||||
// In order of last to first in this file, the default wordlist will be chosen
|
||||
// based on what is present. (Bundles may remove wordlists they don't need)
|
||||
const wordlists: { [index: string]: string[] } = {};
|
||||
let _default: string[] | undefined;
|
||||
try {
|
||||
_default = require('./wordlists/chinese_simplified.json');
|
||||
wordlists.chinese_simplified = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/chinese_traditional.json');
|
||||
wordlists.chinese_traditional = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/korean.json');
|
||||
wordlists.korean = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/french.json');
|
||||
wordlists.french = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/italian.json');
|
||||
wordlists.italian = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/spanish.json');
|
||||
wordlists.spanish = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/japanese.json');
|
||||
wordlists.japanese = _default as string[];
|
||||
wordlists.JA = _default as string[];
|
||||
} catch (err) {}
|
||||
try {
|
||||
_default = require('./wordlists/english.json');
|
||||
wordlists.english = _default as string[];
|
||||
wordlists.EN = _default as string[];
|
||||
} catch (err) {}
|
||||
|
||||
// Last one to overwrite wordlist gets to be default.
|
||||
export { wordlists, _default };
|
|
@ -1,23 +1,18 @@
|
|||
import createHash = require('create-hash');
|
||||
import * as createHash from 'create-hash';
|
||||
import { pbkdf2 as pbkdf2Async, pbkdf2Sync as pbkdf2 } from 'pbkdf2';
|
||||
import randomBytes = require('randombytes');
|
||||
|
||||
import * as randomBytes from 'randombytes';
|
||||
// use unorm until String.prototype.normalize gets better browser support
|
||||
import unorm = require('unorm');
|
||||
import * as unorm from 'unorm';
|
||||
import { _default as _DEFAULT_WORDLIST, wordlists } from './_wordlists';
|
||||
|
||||
import CHINESE_SIMPLIFIED_WORDLIST = require('./wordlists/chinese_simplified.json');
|
||||
import CHINESE_TRADITIONAL_WORDLIST = require('./wordlists/chinese_traditional.json');
|
||||
import ENGLISH_WORDLIST = require('./wordlists/english.json');
|
||||
import FRENCH_WORDLIST = require('./wordlists/french.json');
|
||||
import ITALIAN_WORDLIST = require('./wordlists/italian.json');
|
||||
import JAPANESE_WORDLIST = require('./wordlists/japanese.json');
|
||||
import KOREAN_WORDLIST = require('./wordlists/korean.json');
|
||||
import SPANISH_WORDLIST = require('./wordlists/spanish.json');
|
||||
const DEFAULT_WORDLIST = ENGLISH_WORDLIST;
|
||||
let DEFAULT_WORDLIST: string[] | undefined = _DEFAULT_WORDLIST;
|
||||
|
||||
const INVALID_MNEMONIC = 'Invalid mnemonic';
|
||||
const INVALID_ENTROPY = 'Invalid entropy';
|
||||
const INVALID_CHECKSUM = 'Invalid mnemonic checksum';
|
||||
const WORDLIST_REQUIRED =
|
||||
'A wordlist is required but a default could not be found.\n' +
|
||||
'Please explicitly pass a 2048 word array explicitly.';
|
||||
|
||||
function lpad(str: string, padString: string, length: number): string {
|
||||
while (str.length < length) str = padString + str;
|
||||
|
@ -97,6 +92,9 @@ export function mnemonicToEntropy(
|
|||
wordlist?: string[],
|
||||
): string {
|
||||
wordlist = wordlist || DEFAULT_WORDLIST;
|
||||
if (!wordlist) {
|
||||
throw new Error(WORDLIST_REQUIRED);
|
||||
}
|
||||
|
||||
const words = unorm.nfkd(mnemonic).split(' ');
|
||||
if (words.length % 3 !== 0) throw new Error(INVALID_MNEMONIC);
|
||||
|
@ -135,6 +133,9 @@ export function entropyToMnemonic(
|
|||
): string {
|
||||
if (!Buffer.isBuffer(entropy)) entropy = Buffer.from(entropy, 'hex');
|
||||
wordlist = wordlist || DEFAULT_WORDLIST;
|
||||
if (!wordlist) {
|
||||
throw new Error(WORDLIST_REQUIRED);
|
||||
}
|
||||
|
||||
// 128 <= ENT <= 256
|
||||
if (entropy.length < 16) throw new TypeError(INVALID_ENTROPY);
|
||||
|
@ -151,7 +152,7 @@ export function entropyToMnemonic(
|
|||
return wordlist![index];
|
||||
});
|
||||
|
||||
return wordlist === JAPANESE_WORDLIST
|
||||
return wordlist[0] === '\u3042\u3044\u3053\u304f\u3057\u3093' // Japanese wordlist
|
||||
? words.join('\u3000')
|
||||
: words.join(' ');
|
||||
}
|
||||
|
@ -181,16 +182,9 @@ export function validateMnemonic(
|
|||
return true;
|
||||
}
|
||||
|
||||
export const wordlists = {
|
||||
EN: ENGLISH_WORDLIST,
|
||||
JA: JAPANESE_WORDLIST,
|
||||
export function setDefaultWordlist(language: string): void {
|
||||
const result = wordlists[language];
|
||||
if (result) DEFAULT_WORDLIST = result;
|
||||
}
|
||||
|
||||
chinese_simplified: CHINESE_SIMPLIFIED_WORDLIST,
|
||||
chinese_traditional: CHINESE_TRADITIONAL_WORDLIST,
|
||||
english: ENGLISH_WORDLIST,
|
||||
french: FRENCH_WORDLIST,
|
||||
italian: ITALIAN_WORDLIST,
|
||||
japanese: JAPANESE_WORDLIST,
|
||||
korean: KOREAN_WORDLIST,
|
||||
spanish: SPANISH_WORDLIST,
|
||||
};
|
||||
export { wordlists } from './_wordlists';
|
||||
|
|
|
@ -24,7 +24,8 @@
|
|||
"resolveJsonModule": true
|
||||
},
|
||||
"include": [
|
||||
"ts_src/**/*.ts"
|
||||
"ts_src/**/*.ts",
|
||||
"ts_src/**/*.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/*.spec.ts",
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
declare const wordlists: {
|
||||
[index: string]: string[];
|
||||
};
|
||||
declare let _default: string[] | undefined;
|
||||
export { wordlists, _default };
|
|
@ -7,15 +7,5 @@ export declare function mnemonicToEntropy(mnemonic: string, wordlist?: string[])
|
|||
export declare function entropyToMnemonic(entropy: Buffer | string, wordlist?: string[]): string;
|
||||
export declare function generateMnemonic(strength?: number, rng?: (size: number) => Buffer, wordlist?: string[]): string;
|
||||
export declare function validateMnemonic(mnemonic: string, wordlist?: string[]): boolean;
|
||||
export declare const wordlists: {
|
||||
EN: string[];
|
||||
JA: string[];
|
||||
chinese_simplified: string[];
|
||||
chinese_traditional: string[];
|
||||
english: string[];
|
||||
french: string[];
|
||||
italian: string[];
|
||||
japanese: string[];
|
||||
korean: string[];
|
||||
spanish: string[];
|
||||
};
|
||||
export declare function setDefaultWordlist(language: string): void;
|
||||
export { wordlists } from './_wordlists';
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
declare const wordlists: {
|
||||
[index: string]: string[];
|
||||
};
|
||||
declare let _default: string[] | undefined;
|
||||
export { wordlists, _default };
|
Loading…
Reference in New Issue