mirror of
https://github.com/orbitdb/orbitdb.git
synced 2025-10-07 22:57:07 +00:00
refactor: wip.
This commit is contained in:
parent
4b8379cbbb
commit
be2d5900de
160
src/key-store.js
160
src/key-store.js
@ -1,9 +1,6 @@
|
|||||||
import { Level } from 'level'
|
|
||||||
import * as crypto from '@libp2p/crypto'
|
import * as crypto from '@libp2p/crypto'
|
||||||
import secp256k1 from 'secp256k1'
|
import secp256k1 from 'secp256k1'
|
||||||
import LRU from 'lru'
|
|
||||||
import { Buffer } from 'safe-buffer'
|
import { Buffer } from 'safe-buffer'
|
||||||
import fs from 'fs'
|
|
||||||
import pkg from 'elliptic'
|
import pkg from 'elliptic'
|
||||||
const { ec: EC } = pkg
|
const { ec: EC } = pkg
|
||||||
|
|
||||||
@ -39,53 +36,66 @@ const verifySignature = async (signature, publicKey, data) => {
|
|||||||
return Promise.resolve(res)
|
return Promise.resolve(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
function createStore (path = './keystore') {
|
const sign = async (key, data) => {
|
||||||
if (fs && fs.mkdirSync) {
|
if (!key) {
|
||||||
fs.mkdirSync(path, { recursive: true })
|
throw new Error('No signing key given')
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Level(path, {})
|
if (!data) {
|
||||||
|
throw new Error('Given input data was undefined')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Buffer.isBuffer(data)) {
|
||||||
|
data = Buffer.from(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Buffer.from(await key.sign(data)).toString('hex')
|
||||||
|
}
|
||||||
|
|
||||||
|
const verify = async (signature, publicKey, data) => {
|
||||||
|
// const cached = verifiedCache.get(signature)
|
||||||
|
const cached = null
|
||||||
|
let res = false
|
||||||
|
if (!cached) {
|
||||||
|
const verified = await verifySignature(signature, publicKey, data)
|
||||||
|
res = verified
|
||||||
|
// if (verified) {
|
||||||
|
// verifiedCache.set(signature, { publicKey, data })
|
||||||
|
// }
|
||||||
|
} else {
|
||||||
|
const compare = (cached, data) => {
|
||||||
|
// let match
|
||||||
|
// if (v === 'v0') {
|
||||||
|
// match = Buffer.compare(Buffer.alloc(30, cached), Buffer.alloc(30, data)) === 0
|
||||||
|
// } else {
|
||||||
|
const match = Buffer.isBuffer(data) ? Buffer.compare(cached, data) === 0 : cached === data
|
||||||
|
// }
|
||||||
|
return match
|
||||||
|
}
|
||||||
|
res = cached.publicKey === publicKey && compare(cached.data, data)
|
||||||
|
}
|
||||||
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
// const verifiedCache = new LRU(1000)
|
// const verifiedCache = new LRU(1000)
|
||||||
|
|
||||||
export default class KeyStore {
|
const KeyStore = async ({ storage, cache }) => {
|
||||||
constructor (input = {}) {
|
const close = async () => {
|
||||||
if (typeof input === 'string') {
|
if (!storage) return
|
||||||
this._store = createStore(input)
|
await storage.close()
|
||||||
} else if (typeof input.open === 'function') {
|
|
||||||
this._store = input
|
|
||||||
} else if (typeof input.store === 'string') {
|
|
||||||
this._store = createStore(input.store)
|
|
||||||
} else {
|
|
||||||
this._store = input.store || createStore()
|
|
||||||
}
|
|
||||||
this._cache = input.cache || new LRU(100)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async open () {
|
const hasKey = async (id) => {
|
||||||
if (!this._store) {
|
|
||||||
throw new Error('KeyStore: No store found to open')
|
|
||||||
}
|
|
||||||
await this._store.open()
|
|
||||||
}
|
|
||||||
|
|
||||||
async close () {
|
|
||||||
if (!this._store) return
|
|
||||||
await this._store.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
async hasKey (id) {
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error('id needed to check a key')
|
throw new Error('id needed to check a key')
|
||||||
}
|
}
|
||||||
if (this._store.status && this._store.status !== 'open') {
|
if (storage.status && storage.status !== 'open') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
let hasKey = false
|
let hasKey = false
|
||||||
try {
|
try {
|
||||||
const storedKey = this._cache.get(id) || await this._store.get(id)
|
const storedKey = await cache.get(id) || await storage.get(id)
|
||||||
hasKey = storedKey !== undefined && storedKey !== null
|
hasKey = storedKey !== undefined && storedKey !== null
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Catches 'Error: ENOENT: no such file or directory, open <path>'
|
// Catches 'Error: ENOENT: no such file or directory, open <path>'
|
||||||
@ -95,20 +105,20 @@ export default class KeyStore {
|
|||||||
return hasKey
|
return hasKey
|
||||||
}
|
}
|
||||||
|
|
||||||
async addKey (id, key) {
|
const addKey = async (id, key) => {
|
||||||
try {
|
try {
|
||||||
await this._store.put(id, JSON.stringify(key))
|
await storage.put(id, JSON.stringify(key))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
this._cache.set(id, key)
|
cache.put(id, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
async createKey (id, { entropy } = {}) {
|
const createKey = async (id, { entropy } = {}) => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error('id needed to create a key')
|
throw new Error('id needed to create a key')
|
||||||
}
|
}
|
||||||
// if (this._store.status && this._store.status !== 'open') {
|
// if (storage.status && storage.status !== 'open') {
|
||||||
// console.log("22::", id)
|
// console.log("22::", id)
|
||||||
// return null
|
// return null
|
||||||
// }
|
// }
|
||||||
@ -132,30 +142,30 @@ export default class KeyStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await this._store.put(id, JSON.stringify(key))
|
await storage.put(id, JSON.stringify(key))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.log(e)
|
||||||
}
|
}
|
||||||
this._cache.set(id, key)
|
cache.put(id, key)
|
||||||
|
|
||||||
return keys
|
return keys
|
||||||
}
|
}
|
||||||
|
|
||||||
async getKey (id) {
|
const getKey = async (id) => {
|
||||||
if (!id) {
|
if (!id) {
|
||||||
throw new Error('id needed to get a key')
|
throw new Error('id needed to get a key')
|
||||||
}
|
}
|
||||||
if (!this._store) {
|
if (!storage) {
|
||||||
await this.open()
|
await open()
|
||||||
}
|
}
|
||||||
if (this._store.status && this._store.status !== 'open') {
|
if (storage.status && storage.status !== 'open') {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const cachedKey = this._cache.get(id)
|
const cachedKey = await cache.get(id)
|
||||||
let storedKey
|
let storedKey
|
||||||
try {
|
try {
|
||||||
storedKey = cachedKey || await this._store.get(id)
|
storedKey = cachedKey || await storage.get(id)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// ignore ENOENT error
|
// ignore ENOENT error
|
||||||
}
|
}
|
||||||
@ -170,13 +180,13 @@ export default class KeyStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!cachedKey) {
|
if (!cachedKey) {
|
||||||
this._cache.set(id, deserializedKey)
|
cache.put(id, deserializedKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
return unmarshal(Buffer.from(deserializedKey.privateKey, 'hex'))
|
return unmarshal(Buffer.from(deserializedKey.privateKey, 'hex'))
|
||||||
}
|
}
|
||||||
|
|
||||||
getPublic (keys, options = {}) {
|
const getPublic = (keys, options = {}) => {
|
||||||
const formats = ['hex', 'buffer']
|
const formats = ['hex', 'buffer']
|
||||||
const decompress = typeof options.decompress === 'undefined' ? true : options.decompress
|
const decompress = typeof options.decompress === 'undefined' ? true : options.decompress
|
||||||
const format = options.format || 'hex'
|
const format = options.format || 'hex'
|
||||||
@ -191,44 +201,18 @@ export default class KeyStore {
|
|||||||
return format === 'buffer' ? pubKey : pubKey.toString('hex')
|
return format === 'buffer' ? pubKey : pubKey.toString('hex')
|
||||||
}
|
}
|
||||||
|
|
||||||
static async sign (key, data) {
|
return {
|
||||||
if (!key) {
|
close,
|
||||||
throw new Error('No signing key given')
|
hasKey,
|
||||||
}
|
addKey,
|
||||||
|
createKey,
|
||||||
if (!data) {
|
getKey,
|
||||||
throw new Error('Given input data was undefined')
|
getPublic
|
||||||
}
|
|
||||||
|
|
||||||
if (!Buffer.isBuffer(data)) {
|
|
||||||
data = Buffer.from(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
return Buffer.from(await key.sign(data)).toString('hex')
|
|
||||||
}
|
|
||||||
|
|
||||||
static async verify (signature, publicKey, data) {
|
|
||||||
// const cached = verifiedCache.get(signature)
|
|
||||||
const cached = null
|
|
||||||
let res = false
|
|
||||||
if (!cached) {
|
|
||||||
const verified = await verifySignature(signature, publicKey, data)
|
|
||||||
res = verified
|
|
||||||
// if (verified) {
|
|
||||||
// verifiedCache.set(signature, { publicKey, data })
|
|
||||||
// }
|
|
||||||
} else {
|
|
||||||
const compare = (cached, data) => {
|
|
||||||
// let match
|
|
||||||
// if (v === 'v0') {
|
|
||||||
// match = Buffer.compare(Buffer.alloc(30, cached), Buffer.alloc(30, data)) === 0
|
|
||||||
// } else {
|
|
||||||
const match = Buffer.isBuffer(data) ? Buffer.compare(cached, data) === 0 : cached === data
|
|
||||||
// }
|
|
||||||
return match
|
|
||||||
}
|
|
||||||
res = cached.publicKey === publicKey && compare(cached.data, data)
|
|
||||||
}
|
|
||||||
return res
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
KeyStore as default,
|
||||||
|
verify,
|
||||||
|
sign
|
||||||
|
}
|
||||||
|
32
test/key-store.test.js
Normal file
32
test/key-store.test.js
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
import { deepStrictEqual } from 'assert'
|
||||||
|
import LevelStorage from '../src/storage/level.js'
|
||||||
|
import LRUStorage from '../src/storage/lru.js'
|
||||||
|
import KeyStore from '../src/key-store.js'
|
||||||
|
import { config, testAPIs } from 'orbit-db-test-utils'
|
||||||
|
// import { userA } from '../fixtures/orbit-db-identity-keys.js'
|
||||||
|
|
||||||
|
Object.keys(testAPIs).forEach((IPFS) => {
|
||||||
|
describe('KeyStore (' + IPFS + ')', () => {
|
||||||
|
let keystore
|
||||||
|
beforeEach(async () => {
|
||||||
|
const storage = await LevelStorage('./keys_1')
|
||||||
|
const cache = await LRUStorage(100)
|
||||||
|
keystore = await KeyStore({ storage, cache })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('creates a key', async () => {
|
||||||
|
const id = 'key1'
|
||||||
|
console.log(await keystore.createKey(id))
|
||||||
|
})
|
||||||
|
|
||||||
|
it('gets a key', async () => {
|
||||||
|
const id = 'key1'
|
||||||
|
const keys = await keystore.createKey(id)
|
||||||
|
deepStrictEqual(await keystore.getKey(id), keys)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
keystore.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
Loading…
x
Reference in New Issue
Block a user