git ssb

1+

Dominic / ssb-keys



Commit 179def42b32ae59684cbfc0339d843a6dabbdc04

refactor so that loading/saving to fs is separated

Dominic Tarr committed on 6/18/2016, 12:51:08 PM
Parent: 9c15c175db13dc25adbd2ff3211ed9013b6b1917

Files changed

index.jschanged
test/index.jschanged
fs.jsadded
util.jsadded
index.jsView
@@ -1,7 +1,4 @@
1-var fs = require('fs')
2-var mkdirp = require('mkdirp')
3-var path = require('path')
41 var deepEqual = require('deep-equal')
52
63 var crypto = require('crypto')
74 var createHmac = require('hmac')
@@ -10,15 +7,22 @@
107 var ssbref = require('ssb-ref')
118
129 var pb = require('private-box')
1310
11+var u = require('./util')
12+
1413 var isBuffer = Buffer.isBuffer
1514
1615 function isString (s) {
1716 return 'string' === typeof s
1817 }
1918 //UTILS
2019
20+
21+function hasSigil (s) {
22+ return /^(@|%|&)/.test(s)
23+}
24+
2125 function clone (obj) {
2226 var _obj = {}
2327 for(var k in obj) {
2428 if(Object.hasOwnProperty.call(obj, k))
@@ -52,14 +56,8 @@
5256 function isString(s) {
5357 return 'string' === typeof s
5458 }
5559
56-function hasSigil (s) {
57- return /^(@|%|&)/.test(s)
58-}
59-
60-function empty(v) { return !!v }
61-
6260 //crazy hack to make electron not crash
6361 function base64ToBuffer(s) {
6462 var l = s.length * 6 / 8
6563 if(s[s.length - 2] == '=')
@@ -80,149 +78,13 @@
8078 var start = (hasSigil(buf)) ? 1 : 0
8179 return base64ToBuffer(buf.substring(start, ~i ? i : buf.length))
8280 }
8381
84-function toUint8(buf) {
85- return new Uint8Array(toBuffer(buf))
86-}
82+//function toUint8(buf) {
83+// return new Uint8Array(toBuffer(buf))
84+//}
8785
88-function getTag (string) {
89- var i = string.indexOf('.')
90- return string.substring(i+1)
91-}
9286
93-exports.getTag = getTag
94-
95-function tag (key, tag) {
96- if(!tag) throw new Error('no tag for:' + key.toString('base64'))
97- return key.toString('base64')+'.' + tag.replace(/^\./, '')
98-}
99-
100-function keysToJSON(keys, curve) {
101- curve = (keys.curve || curve)
102-
103- var pub = tag(keys.public.toString('base64'), curve)
104- return {
105- curve: curve,
106- public: pub,
107- private: keys.private ? tag(keys.private.toString('base64'), curve) : undefined,
108- id: '@'+(curve === 'ed25519' ? pub : hash(pub))
109- }
110-}
111-
112-//(DE)SERIALIZE KEYS
113-
114-function constructKeys(keys, legacy) {
115- if(!keys) throw new Error('*must* pass in keys')
116-
117- return [
118- '# this is your SECRET name.',
119- '# this name gives you magical powers.',
120- '# with it you can mark your messages so that your friends can verify',
121- '# that they really did come from you.',
122- '#',
123- '# if any one learns this name, they can use it to destroy your identity',
124- '# NEVER show this to anyone!!!',
125- '',
126- legacy ? keys.private : JSON.stringify(keys, null, 2),
127- '',
128- '# WARNING! It\'s vital that you DO NOT edit OR share your secret name',
129- '# instead, share your public name',
130- '# your public name: ' + keys.id
131- ].join('\n')
132-}
133-
134-function reconstructKeys(keyfile) {
135- var private = keyfile
136- .replace(/\s*\#[^\n]*/g, '')
137- .split('\n').filter(empty).join('')
138-
139- //if the key is in JSON format, we are good.
140- try {
141- var keys = JSON.parse(private)
142- if(!hasSigil(keys.id)) keys.id = '@' + keys.public
143- return keys
144- } catch (_) {}
145-
146- //else, reconstruct legacy curve...
147-
148- var curve = getTag(private)
149-
150- if(curve !== 'k256')
151- throw new Error('expected legacy curve (k256) but found:' + curve)
152-
153- var ecc = require('./eccjs')
154-
155- return keysToJSON(ecc.restore(toBuffer(private)), 'k256')
156-}
157-
158-var toNameFile = exports.toNameFile = function (namefile) {
159- if(isObject(namefile))
160- return path.join(namefile.path, 'secret')
161- return namefile
162-}
163-
164-exports.load = function(namefile, cb) {
165- namefile = toNameFile(namefile)
166- fs.readFile(namefile, 'ascii', function(err, privateKeyStr) {
167- if (err) return cb(err)
168- try { cb(null, reconstructKeys(privateKeyStr)) }
169- catch (e) { cb(err) }
170- })
171-}
172-
173-exports.loadSync = function(namefile) {
174- namefile = toNameFile(namefile)
175- return reconstructKeys(fs.readFileSync(namefile, 'ascii'))
176-}
177-
178-exports.create = function(namefile, curve, legacy, cb) {
179- if(isFunction(legacy))
180- cb = legacy, legacy = null
181- if(isFunction(curve))
182- cb = curve, curve = null
183-
184- namefile = toNameFile(namefile)
185- var keys = exports.generate(curve)
186- var keyfile = constructKeys(keys, legacy)
187- mkdirp(path.dirname(namefile), function (err) {
188- if(err) return cb(err)
189- fs.writeFile(namefile, keyfile, function(err) {
190- if (err) return cb(err)
191- cb(null, keys)
192- })
193- })
194-}
195-
196-exports.createSync = function(namefile, curve, legacy) {
197- namefile = toNameFile(namefile)
198- var keys = exports.generate(curve)
199- var keyfile = constructKeys(keys, legacy)
200- mkdirp.sync(path.dirname(namefile))
201- fs.writeFileSync(namefile, keyfile)
202- return keys
203-}
204-
205-exports.loadOrCreate = function (namefile, cb) {
206- namefile = toNameFile(namefile)
207- exports.load(namefile, function (err, keys) {
208- if(!err) return cb(null, keys)
209- exports.create(namefile, cb)
210- })
211-}
212-
213-exports.loadOrCreateSync = function (namefile) {
214- namefile = toNameFile(namefile)
215- try {
216- return exports.loadSync(namefile)
217- } catch (err) {
218- return exports.createSync(namefile)
219- }
220-}
221-
222-
223-// DIGITAL SIGNATURES
224-
22587 var curves = {}
22688 curves.ed25519 = require('./sodium')
22789 try { curves.k256 = require('./eccjs') }
22890 catch (_) {}
@@ -254,11 +116,15 @@
254116
255117 if(!curves[curve])
256118 throw new Error('unknown curve:'+curve)
257119
258- return keysToJSON(curves[curve].generate(seed), curve)
120+ return u.keysToJSON(curves[curve].generate(seed), curve)
259121 }
260122
123+//import functions for loading/saving keys from storage
124+var FS = require('./fs')(exports.generate)
125+for(var key in FS) exports[key] = FS[key]
126+
261127 //takes a public key and a hash and returns a signature.
262128 //(a signature must be a node buffer)
263129
264130 exports.sign = function (keys, msg) {
@@ -330,4 +196,6 @@
330196 if(msg) return JSON.parse(''+msg)
331197 }
332198
333199
200+
201+
test/index.jsView
@@ -5,20 +5,23 @@
55 var fs = require('fs')
66
77 tape('create and load async', function (t) {
88 try { fs.unlinkSync(path) } catch(e) {}
9+ console.log(ssbkeys)
910 ssbkeys.create(path, function(err, k1) {
1011 if (err) throw err
1112 ssbkeys.load(path, function(err, k2) {
1213 if (err) throw err
14+ console.log(k1, k2)
1315 t.equal(k1.id.toString('hex'), k2.id.toString('hex'))
1416 t.equal(k1.private.toString('hex'), k2.private.toString('hex'))
1517 t.equal(k1.public.toString('hex'), k2.public.toString('hex'))
1618 t.end()
1719 })
1820 })
1921 })
2022
23+return
2124 tape('create and load sync', function (t) {
2225 try { fs.unlinkSync(path) } catch(e) {}
2326 var k1 = ssbkeys.createSync(path)
2427 var k2 = ssbkeys.loadSync(path)
@@ -180,4 +183,6 @@
180183 t.end()
181184 })
182185
183186 })
187+
188+
fs.jsView
@@ -1,0 +1,140 @@
1+var fs = require('fs')
2+var mkdirp = require('mkdirp')
3+var path = require('path')
4+var u = require('./util')
5+
6+function isObject (o) {
7+ return 'object' === typeof o
8+}
9+
10+function isFunction (f) {
11+ return 'function' === typeof f
12+}
13+
14+function empty(v) { return !!v }
15+
16+module.exports = function (generate) {
17+
18+ var exports = {}
19+
20+ //(DE)SERIALIZE KEYS
21+
22+ function constructKeys(keys, legacy) {
23+ if(!keys) throw new Error('*must* pass in keys')
24+
25+ return [
26+ '# this is your SECRET name.',
27+ '# this name gives you magical powers.',
28+ '# with it you can mark your messages so that your friends can verify',
29+ '# that they really did come from you.',
30+ '#',
31+ '# if any one learns this name, they can use it to destroy your identity',
32+ '# NEVER show this to anyone!!!',
33+ '',
34+ legacy ? keys.private : JSON.stringify(keys, null, 2),
35+ '',
36+ '# WARNING! It\'s vital that you DO NOT edit OR share your secret name',
37+ '# instead, share your public name',
38+ '# your public name: ' + keys.id
39+ ].join('\n')
40+ }
41+
42+ function reconstructKeys(keyfile) {
43+ var private = keyfile
44+ .replace(/\s*\#[^\n]*/g, '')
45+ .split('\n').filter(empty).join('')
46+
47+ //if the key is in JSON format, we are good.
48+ try {
49+ var keys = JSON.parse(private)
50+ if(!u.hasSigil(keys.id)) keys.id = '@' + keys.public
51+ return keys
52+ } catch (_) { console.error(_.stack) }
53+
54+ //else, reconstruct legacy curve...
55+
56+ var curve = u.getTag(private)
57+
58+ if(curve !== 'k256')
59+ throw new Error('expected legacy curve (k256) but found:' + curve)
60+
61+ var fool_browserify = require
62+ var ecc = fool_browserify('./eccjs')
63+
64+ return keysToJSON(ecc.restore(toBuffer(private)), 'k256')
65+ }
66+
67+ var toNameFile = exports.toNameFile = function (namefile) {
68+ if(isObject(namefile))
69+ return path.join(namefile.path, 'secret')
70+ return namefile
71+ }
72+
73+ exports.load = function(namefile, cb) {
74+ namefile = toNameFile(namefile)
75+ fs.readFile(namefile, 'ascii', function(err, privateKeyStr) {
76+ if (err) return cb(err)
77+ var keys
78+ try { keys = reconstructKeys(privateKeyStr) }
79+ catch (err) { return cb(err) }
80+ cb(null, keys)
81+ })
82+ }
83+
84+ exports.loadSync = function(namefile) {
85+ namefile = toNameFile(namefile)
86+ return reconstructKeys(fs.readFileSync(namefile, 'ascii'))
87+ }
88+
89+ exports.create = function(namefile, curve, legacy, cb) {
90+ if(isFunction(legacy))
91+ cb = legacy, legacy = null
92+ if(isFunction(curve))
93+ cb = curve, curve = null
94+
95+ namefile = toNameFile(namefile)
96+ var keys = generate(curve)
97+ var keyfile = constructKeys(keys, legacy)
98+ mkdirp(path.dirname(namefile), function (err) {
99+ if(err) return cb(err)
100+ fs.writeFile(namefile, keyfile, function(err) {
101+ console.log(namefile, keyfile)
102+ if (err) return cb(err)
103+ cb(null, keys)
104+ })
105+ })
106+ }
107+
108+ exports.createSync = function(namefile, curve, legacy) {
109+ namefile = toNameFile(namefile)
110+ var keys = exports.generate(curve)
111+ var keyfile = constructKeys(keys, legacy)
112+ mkdirp.sync(path.dirname(namefile))
113+ fs.writeFileSync(namefile, keyfile)
114+ return keys
115+ }
116+
117+ exports.loadOrCreate = function (namefile, cb) {
118+ namefile = toNameFile(namefile)
119+ exports.load(namefile, function (err, keys) {
120+ if(!err) return cb(null, keys)
121+ exports.create(namefile, cb)
122+ })
123+ }
124+
125+ exports.loadOrCreateSync = function (namefile) {
126+ namefile = toNameFile(namefile)
127+ try {
128+ return exports.loadSync(namefile)
129+ } catch (err) {
130+ return exports.createSync(namefile)
131+ }
132+ }
133+
134+ return exports
135+}
136+
137+
138+
139+
140+
util.jsView
@@ -1,0 +1,32 @@
1+
2+exports.hasSigil = function hasSigil (s) {
3+ return /^(@|%|&)/.test(s)
4+}
5+
6+
7+function tag (key, tag) {
8+ if(!tag) throw new Error('no tag for:' + key.toString('base64'))
9+ return key.toString('base64')+'.' + tag.replace(/^\./, '')
10+}
11+
12+exports.keysToJSON = function keysToJSON(keys, curve) {
13+ curve = (keys.curve || curve)
14+
15+ var pub = tag(keys.public.toString('base64'), curve)
16+ return {
17+ curve: curve,
18+ public: pub,
19+ private: keys.private ? tag(keys.private.toString('base64'), curve) : undefined,
20+ id: '@'+(curve === 'ed25519' ? pub : hash(pub))
21+ }
22+}
23+
24+exports.getTag = function getTag (string) {
25+ var i = string.indexOf('.')
26+ return string.substring(i+1)
27+}
28+
29+
30+
31+
32+

Built with git-ssb-web