mirror of
https://github.com/amark/gun.git
synced 2025-06-06 14:16:44 +00:00
secret, clean
This commit is contained in:
parent
d42ed3ff95
commit
c1c00595b8
2005
lib/cryptomodules.js
2005
lib/cryptomodules.js
File diff suppressed because one or more lines are too long
102
lib/s3.js
102
lib/s3.js
@ -1,102 +0,0 @@
|
|||||||
;(function(){
|
|
||||||
|
|
||||||
var Gun = require('../gun');
|
|
||||||
var S3 = require('./aws');
|
|
||||||
|
|
||||||
// TODO: BUG! Mark, upgrade S3 in v0.8.X! And try to integrate with Radix Storage Engine!!!
|
|
||||||
|
|
||||||
Gun.on('opt', function(ctx){
|
|
||||||
this.to.next(ctx);
|
|
||||||
var opt = ctx.opt;
|
|
||||||
if(ctx.once){ return }
|
|
||||||
if(!process.env.AWS_S3_BUCKET){ return }
|
|
||||||
console.log("S3 STORAGE ENGINE IS BROKEN IN 0.8! DO NOT USE UNTIL FIXED!");
|
|
||||||
var s3 = opt.store || S3(opt.s3 = opt.s3 || {});
|
|
||||||
opt.s3.store = s3;
|
|
||||||
if(!s3 || !s3.config){ return Gun.log("No S3 config!") }
|
|
||||||
opt.file = opt.file || opt.prefix || '';
|
|
||||||
opt.batch = opt.batch || 10;
|
|
||||||
opt.throttle = opt.throttle || process.env.AWS_S3_THROTTLE || 15;
|
|
||||||
opt.disconnect = opt.disconnect || 5;
|
|
||||||
ctx.on('get', function(at){
|
|
||||||
this.to.next(at);
|
|
||||||
var id = at['#'], soul = at.get['#'], field = at.get['.'];
|
|
||||||
var key = opt.prefix+soul;
|
|
||||||
s3.GET(key, function(err, data, text, meta){
|
|
||||||
meta = meta || {};
|
|
||||||
if(err && err.statusCode == 404){
|
|
||||||
err = null; // we want a difference between 'unfound' (data is null) and 'error' (auth is wrong).
|
|
||||||
}
|
|
||||||
if(!data){
|
|
||||||
data = root._.graph[soul] || async[soul];
|
|
||||||
}
|
|
||||||
if(data && !Gun.node.soul(data)){
|
|
||||||
err = {err: Gun.log('No soul on S3 node data!')};
|
|
||||||
}
|
|
||||||
if(err){
|
|
||||||
root.on('in', {'@': id, err: err});
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var node = data;
|
|
||||||
graph[soul] = true;
|
|
||||||
if(data && field){
|
|
||||||
node = Gun.state.ify({}, field, Gun.state.is(node, field), node[field], soul);
|
|
||||||
}
|
|
||||||
console.log("got", soul, node);
|
|
||||||
root.on('in', {'@': id, put: Gun.graph.node(node)});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ctx.on('put', function(at){
|
|
||||||
this.to.next(at);
|
|
||||||
var id = at['#'], check = {}, next = s3.next, err, u;
|
|
||||||
Gun.graph.is(at.put, null, function(val, key, node, soul){
|
|
||||||
batch[soul] = Gun.state.to(node, key, disk[soul]);
|
|
||||||
});
|
|
||||||
if(!at['@']){ acks[at['#']] = true; } // only ack non-acks.
|
|
||||||
s3.batching += 1;
|
|
||||||
if(opt.batch < s3.batching){
|
|
||||||
return now();
|
|
||||||
}
|
|
||||||
if(!opt.throttle){
|
|
||||||
return now();
|
|
||||||
}
|
|
||||||
s3.wait = s3.wait || setTimeout(now, opt.throttle * 1000); // in seconds
|
|
||||||
});
|
|
||||||
function now(){
|
|
||||||
clearTimeout(s3.wait);
|
|
||||||
var keep = batch;
|
|
||||||
batch = {};
|
|
||||||
s3.batching = 0;
|
|
||||||
var now = s3.next;
|
|
||||||
s3.next = Gun.time.is();
|
|
||||||
s3.wait = null;
|
|
||||||
Gun.obj.map(keep, function put(exists, soul, count){
|
|
||||||
console.log("s3ving...", soul);
|
|
||||||
var node = root._.graph[soul] || async[soul]; // the batch does not actually have the nodes, but what happens when we do cold data? Could this be gone?
|
|
||||||
s3.PUT(opt.prefix+soul, node, function(err, reply){
|
|
||||||
if(count < 5 && (err || !reply)){
|
|
||||||
put(exists, soul, (count || 0) + 1); // naive implementation of retry TODO: BUG: need backoff and anti-infinite-loop!
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
//console.log("S3VED", soul);
|
|
||||||
s3.on(now + ':' + soul, [err, reply]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var graph = {}, batch = {}, acks = {}, ids = {}, async = {};
|
|
||||||
var count = 0;
|
|
||||||
s3.next = s3.next || Gun.time.is();
|
|
||||||
s3.on = s3.on || Gun.on;
|
|
||||||
});
|
|
||||||
|
|
||||||
;(function(){return;
|
|
||||||
global.Gun = require('../gun');
|
|
||||||
|
|
||||||
process.env.AWS_S3_BUCKET = 'test-s3';
|
|
||||||
process.env.AWS_ACCESS_KEY_ID = 'asdf';
|
|
||||||
process.env.AWS_SECRET_ACCESS_KEY = 'fdsa';
|
|
||||||
process.env.fakes3 = 'http://localhost:4567';
|
|
||||||
process.env.AWS_S3_THROTTLE = 0;
|
|
||||||
require('../test/abc');
|
|
||||||
}());
|
|
||||||
}());
|
|
@ -1,41 +0,0 @@
|
|||||||
|
|
||||||
import fs from 'fs'
|
|
||||||
|
|
||||||
let dirname // TODO: where did __dirname go ?
|
|
||||||
|
|
||||||
const serve = (req, res, nxt) => {
|
|
||||||
if (!req || !res) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const next = nxt || serve
|
|
||||||
|
|
||||||
if (!req.url) {
|
|
||||||
return next()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 <= req.url.indexOf('gun.js')) {
|
|
||||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
|
||||||
res.end(serve.js = serve.js || fs.readFileSync(dirname + '/gun.js'))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if (0 <= req.url.indexOf('gun/')) {
|
|
||||||
res.writeHead(200, { 'Content-Type': 'text/javascript' })
|
|
||||||
var path = dirname + '/' + req.url.split('/').slice(2).join('/'), file
|
|
||||||
try {
|
|
||||||
file = fs.readFileSync(path)
|
|
||||||
} catch(e) {} // eslint-disable-line no-empty
|
|
||||||
if (file) {
|
|
||||||
res.end(file)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return next()
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (dir) => {
|
|
||||||
dirname = dir
|
|
||||||
return serve
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
|
|
||||||
import serve from './serve'
|
|
||||||
|
|
||||||
export default (Gun, dir) => { // TODO: where did __dirname go ?
|
|
||||||
Gun.serve = serve(dir)
|
|
||||||
return Gun
|
|
||||||
}
|
|
@ -39,6 +39,13 @@
|
|||||||
const { epub } = at.put
|
const { epub } = at.put
|
||||||
// TODO: 'salt' needed?
|
// TODO: 'salt' needed?
|
||||||
err = null
|
err = null
|
||||||
|
if(typeof window !== 'undefined'){
|
||||||
|
var tmp = window.sessionStorage;
|
||||||
|
if(tmp && gunRoot._.opt.remember){
|
||||||
|
window.sessionStorage.alias = alias;
|
||||||
|
window.sessionStorage.tmp = pass;
|
||||||
|
}
|
||||||
|
}
|
||||||
return Object.assign(props, { priv, salt, epub, epriv })
|
return Object.assign(props, { priv, salt, epub, epriv })
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
err = 'Failed to decrypt secret!'
|
err = 'Failed to decrypt secret!'
|
||||||
|
@ -14,13 +14,6 @@
|
|||||||
// persist authentication
|
// persist authentication
|
||||||
//await authPersist(user._, key.proof, opts) // temporarily disabled
|
//await authPersist(user._, key.proof, opts) // temporarily disabled
|
||||||
// emit an auth event, useful for page redirects and stuff.
|
// emit an auth event, useful for page redirects and stuff.
|
||||||
if(typeof window !== 'undefined'){
|
|
||||||
var tmp = window.sessionStorage;
|
|
||||||
if(tmp && gunRoot._.opt.remember){
|
|
||||||
window.sessionStorage.alias = alias;
|
|
||||||
window.sessionStorage.tmp = key;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
gunRoot._.on('auth', user._)
|
gunRoot._.on('auth', user._)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
32
sea/sea.js
32
sea/sea.js
@ -65,38 +65,6 @@
|
|||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Derive shared secret from other's pub and my epub/epriv
|
|
||||||
SEA.derive = async (pub, { epub, epriv }) => {
|
|
||||||
try {
|
|
||||||
const ecdhSubtle = ossl || subtle
|
|
||||||
const keysToEcdhJwk = (pub, d) => { // d === priv
|
|
||||||
const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':')
|
|
||||||
const jwk = d ? { d } : {}
|
|
||||||
return [ // Use with spread returned value...
|
|
||||||
'jwk',
|
|
||||||
{ ...jwk, x, y, kty: 'EC', crv: 'P-256', ext: true },
|
|
||||||
ecdhKeyProps
|
|
||||||
]
|
|
||||||
}
|
|
||||||
const pubKeyData = keysToEcdhJwk(pub)
|
|
||||||
const props = {
|
|
||||||
...ecdhKeyProps,
|
|
||||||
public: await ecdhSubtle.importKey(...pubKeyData, true, [])
|
|
||||||
}
|
|
||||||
const privKeyData = keysToEcdhJwk(epub, epriv)
|
|
||||||
const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey'])
|
|
||||||
.then(async (privKey) => {
|
|
||||||
// privateKey scope doesn't leak out from here!
|
|
||||||
const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-CBC', length: 256 }, true, [ 'encrypt', 'decrypt' ])
|
|
||||||
return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k)
|
|
||||||
})
|
|
||||||
return derived
|
|
||||||
} catch (e) {
|
|
||||||
console.log(e)
|
|
||||||
throw e
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// all done!
|
// all done!
|
||||||
// Obviously it is missing MANY necessary features. This is only an alpha release.
|
// Obviously it is missing MANY necessary features. This is only an alpha release.
|
||||||
// Please experiment with it, audit what I've done so far, and complain about what needs to be added.
|
// Please experiment with it, audit what I've done so far, and complain about what needs to be added.
|
||||||
|
44
sea/secret.js
Normal file
44
sea/secret.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
|
||||||
|
var SEA = require('./root');
|
||||||
|
var shim = require('./shim');
|
||||||
|
var S = require('./settings');
|
||||||
|
// Derive shared secret from other's pub and my epub/epriv
|
||||||
|
SEA.secret = async (key, pair, cb) => { try {
|
||||||
|
const pub = key.epub || key
|
||||||
|
const epub = pair.epub
|
||||||
|
const epriv = pair.epriv
|
||||||
|
const ecdhSubtle = shim.ossl || shim.subtle
|
||||||
|
const pubKeyData = keysToEcdhJwk(pub)
|
||||||
|
const props = {
|
||||||
|
...S.ecdh,
|
||||||
|
public: await ecdhSubtle.importKey(...pubKeyData, true, [])
|
||||||
|
}
|
||||||
|
const privKeyData = keysToEcdhJwk(epub, epriv)
|
||||||
|
const derived = await ecdhSubtle.importKey(...privKeyData, false, ['deriveKey'])
|
||||||
|
.then(async (privKey) => {
|
||||||
|
// privateKey scope doesn't leak out from here!
|
||||||
|
const derivedKey = await ecdhSubtle.deriveKey(props, privKey, { name: 'AES-CBC', length: 256 }, true, [ 'encrypt', 'decrypt' ])
|
||||||
|
return ecdhSubtle.exportKey('jwk', derivedKey).then(({ k }) => k)
|
||||||
|
})
|
||||||
|
const r = derived;
|
||||||
|
if(cb){ cb(r) }
|
||||||
|
return r;
|
||||||
|
} catch(e) {
|
||||||
|
SEA.err = e;
|
||||||
|
if(cb){ cb() }
|
||||||
|
return;
|
||||||
|
}}
|
||||||
|
|
||||||
|
const keysToEcdhJwk = (pub, d) => { // d === priv
|
||||||
|
//const [ x, y ] = Buffer.from(pub, 'base64').toString('utf8').split(':') // old
|
||||||
|
const [ x, y ] = pub.split('.') // new
|
||||||
|
const jwk = d ? { d } : {}
|
||||||
|
return [ // Use with spread returned value...
|
||||||
|
'jwk',
|
||||||
|
{ ...jwk, x, y, kty: 'EC', crv: 'P-256', ext: true }, // ??? refactor
|
||||||
|
S.ecdh
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = SEA.secret;
|
||||||
|
|
@ -138,8 +138,8 @@
|
|||||||
const salt = Gun.text.random(64);
|
const salt = Gun.text.random(64);
|
||||||
const encSigAuth = await SEA.work(newpass, salt)
|
const encSigAuth = await SEA.work(newpass, salt)
|
||||||
.then((key) =>
|
.then((key) =>
|
||||||
SEA.encrypt({ priv, epriv }, { pub, key, set: true })
|
SEA.encrypt({ priv, epriv }, key)
|
||||||
.then((auth) => SEA.sign({ salt, auth }, keys))
|
.then((auth) => SEA.sign({ek: auth, s: salt}, keys))
|
||||||
)
|
)
|
||||||
const signedEpub = await SEA.sign(epub, keys)
|
const signedEpub = await SEA.sign(epub, keys)
|
||||||
const signedAlias = await SEA.sign(alias, keys)
|
const signedAlias = await SEA.sign(alias, keys)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user