Compare commits
No commits in common. "db738e978a929c8eeb300723e405efdfa355d095" and "dd8c11bea42b57f0eccf6dec68ebf4637b900243" have entirely different histories.
db738e978a
...
dd8c11bea4
16
.drone.yml
16
.drone.yml
@ -1,16 +0,0 @@
|
|||||||
---
|
|
||||||
kind: pipeline
|
|
||||||
type: docker
|
|
||||||
name: default
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: build
|
|
||||||
image: node:12
|
|
||||||
commands:
|
|
||||||
- npm install
|
|
||||||
- npm run ci
|
|
||||||
---
|
|
||||||
kind: signature
|
|
||||||
hmac: a49a1e7c428472d0237bb2ba73511965607384f45114941b869c6a9eff7aef70
|
|
||||||
|
|
||||||
...
|
|
||||||
@ -1,15 +1,9 @@
|
|||||||
import _debug from 'debug'
|
|
||||||
import socket from '../socket'
|
import socket from '../socket'
|
||||||
import { Dispatch, ThunkResult } from '../store'
|
import { Dispatch, ThunkResult } from '../store'
|
||||||
import { callId } from '../window'
|
import { callId } from '../window'
|
||||||
import { ClientSocket } from '../socket'
|
import { ClientSocket } from '../socket'
|
||||||
import * as NotifyActions from './NotifyActions'
|
import * as NotifyActions from './NotifyActions'
|
||||||
import * as SocketActions from './SocketActions'
|
import * as SocketActions from './SocketActions'
|
||||||
import { generateECDHKeyPair, exportKey } from '../crypto'
|
|
||||||
import { getIdentity, Identity, saveIdentity } from '../db'
|
|
||||||
import { ME } from '../constants'
|
|
||||||
|
|
||||||
const debug = _debug('peercalls')
|
|
||||||
|
|
||||||
export interface InitAction {
|
export interface InitAction {
|
||||||
type: 'INIT'
|
type: 'INIT'
|
||||||
@ -28,11 +22,6 @@ export const init = (): ThunkResult<Promise<void>> =>
|
|||||||
async (dispatch, getState) => {
|
async (dispatch, getState) => {
|
||||||
const socket = await dispatch(connect())
|
const socket = await dispatch(connect())
|
||||||
|
|
||||||
const keyPair = await dispatch(findOrCreateEncryptionKeys())
|
|
||||||
const publicKey = keyPair && await exportKey(keyPair.publicKey)
|
|
||||||
// TODO use publicKey
|
|
||||||
publicKey
|
|
||||||
|
|
||||||
dispatch(SocketActions.handshake({
|
dispatch(SocketActions.handshake({
|
||||||
socket,
|
socket,
|
||||||
roomName: callId,
|
roomName: callId,
|
||||||
@ -54,45 +43,3 @@ export const connect = () => (dispatch: Dispatch) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const findOrCreateEncryptionKeys = () => async (
|
|
||||||
dispatch: Dispatch,
|
|
||||||
): Promise<CryptoKeyPair | undefined> => {
|
|
||||||
|
|
||||||
let identity: Identity | undefined
|
|
||||||
try {
|
|
||||||
identity = await getIdentity(ME)
|
|
||||||
} catch (err) {
|
|
||||||
dispatch(NotifyActions.error('This browser does not support IndexedDB'))
|
|
||||||
debug('IndexedDB error: %s', err)
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
|
|
||||||
if (identity && identity.privateKey) {
|
|
||||||
dispatch(NotifyActions.info('Using encryption keys from IndexedDB'))
|
|
||||||
return {
|
|
||||||
privateKey: identity.privateKey,
|
|
||||||
publicKey: identity.publicKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let keyPair: CryptoKeyPair
|
|
||||||
try {
|
|
||||||
keyPair = await generateECDHKeyPair()
|
|
||||||
} catch (err) {
|
|
||||||
dispatch(NotifyActions.error('Unable to generate encryption keys'))
|
|
||||||
debug('Unable to generate encryption keys: %s', err)
|
|
||||||
return undefined
|
|
||||||
}
|
|
||||||
const { privateKey, publicKey } = keyPair
|
|
||||||
|
|
||||||
identity = {
|
|
||||||
id: ME,
|
|
||||||
privateKey,
|
|
||||||
publicKey,
|
|
||||||
}
|
|
||||||
|
|
||||||
await saveIdentity(identity)
|
|
||||||
|
|
||||||
return keyPair
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { exportKey, encrypt, decrypt, generateECDHKeyPair, deriveECDHKey, hasWebCryptoAPI, importKey } from './index'
|
import { exportPublicKey, encrypt, decrypt, generateECDHKeyPair, deriveECDHKey, hasWebCryptoAPI, importPublicKey } from './index'
|
||||||
|
|
||||||
describe('crypto', () => {
|
describe('crypto', () => {
|
||||||
|
|
||||||
@ -27,11 +27,11 @@ describe('crypto', () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('exportKey and importKey', () => {
|
describe('exportPublicKey and importPublicKey', () => {
|
||||||
it('exports public key', async () => {
|
it('exports public key', async () => {
|
||||||
const value = await exportKey(keypair1.publicKey)
|
const value = await exportPublicKey(keypair1.publicKey)
|
||||||
console.log(value)
|
console.log(value)
|
||||||
const key = await importKey(value)
|
const key = await importPublicKey(value)
|
||||||
expect(key).toBeTruthy()
|
expect(key).toBeTruthy()
|
||||||
expect(key).toEqual(keypair1.publicKey)
|
expect(key).toEqual(keypair1.publicKey)
|
||||||
})
|
})
|
||||||
|
|||||||
@ -13,7 +13,7 @@ export async function generateECDHKeyPair() {
|
|||||||
name: 'ECDH',
|
name: 'ECDH',
|
||||||
namedCurve: 'P-256',
|
namedCurve: 'P-256',
|
||||||
},
|
},
|
||||||
/* extractable */ true,
|
/* extractable */ false,
|
||||||
['deriveKey'],
|
['deriveKey'],
|
||||||
)
|
)
|
||||||
return key
|
return key
|
||||||
@ -34,7 +34,7 @@ export async function deriveECDHKey(params: {
|
|||||||
name: 'AES-CTR',
|
name: 'AES-CTR',
|
||||||
length: 256,
|
length: 256,
|
||||||
},
|
},
|
||||||
/* extractable */ true,
|
/* extractable */ false,
|
||||||
['encrypt', 'decrypt'],
|
['encrypt', 'decrypt'],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -68,8 +68,13 @@ export async function decrypt(key: CryptoKey, data: string): Promise<string> {
|
|||||||
return ab2str(decrypted)
|
return ab2str(decrypted)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function exportKey(key: CryptoKey) {
|
export async function exportPublicKey(key: CryptoKey) {
|
||||||
return await window.crypto.subtle.exportKey('jwk', key)
|
return await window.crypto.subtle.exportKey('jwk', key)
|
||||||
|
// const pkcs8 = await window.crypto.subtle.exportKey('pkcs8', key)
|
||||||
|
// const base64 = window.btoa(ab2str(pkcs8, Uint8Array))
|
||||||
|
// const value =
|
||||||
|
// `-----BEGIN PUBLIC KEY-----\n${base64}\n-----END PUBLIC KEY-----`
|
||||||
|
// return value
|
||||||
}
|
}
|
||||||
|
|
||||||
function ab2str(
|
function ab2str(
|
||||||
@ -80,7 +85,7 @@ function ab2str(
|
|||||||
null, new ArrayType(buf) as unknown as number[])
|
null, new ArrayType(buf) as unknown as number[])
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function importKey(keyData: JsonWebKey) {
|
export async function importPublicKey(keyData: JsonWebKey) {
|
||||||
if (keyData.kty !== 'EC' || keyData.crv !== 'P-256') {
|
if (keyData.kty !== 'EC' || keyData.crv !== 'P-256') {
|
||||||
throw new Error(`Unsupported key type: ${keyData.kty}, crv: ${keyData.crv}`)
|
throw new Error(`Unsupported key type: ${keyData.kty}, crv: ${keyData.crv}`)
|
||||||
}
|
}
|
||||||
@ -92,7 +97,7 @@ export async function importKey(keyData: JsonWebKey) {
|
|||||||
namedCurve: keyData.crv,
|
namedCurve: keyData.crv,
|
||||||
},
|
},
|
||||||
/* extractable */ true,
|
/* extractable */ true,
|
||||||
keyData.key_ops || [],
|
[],
|
||||||
)
|
)
|
||||||
return key
|
return key
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,34 +0,0 @@
|
|||||||
import { getIdentity, saveIdentity } from './identities'
|
|
||||||
import { promisify } from './promisify'
|
|
||||||
import { generateECDHKeyPair } from '../crypto'
|
|
||||||
|
|
||||||
describe('identities', () => {
|
|
||||||
|
|
||||||
const TEST_DB = 'TEST_DB'
|
|
||||||
|
|
||||||
let keyPair: CryptoKeyPair
|
|
||||||
beforeEach(async () => {
|
|
||||||
keyPair = await generateECDHKeyPair()
|
|
||||||
})
|
|
||||||
afterEach(async () => {
|
|
||||||
await promisify(window.indexedDB.deleteDatabase(TEST_DB))
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('getIdentity', () => {
|
|
||||||
it('reads saved identity', async () => {
|
|
||||||
const identity = {
|
|
||||||
id: 'one',
|
|
||||||
...keyPair,
|
|
||||||
}
|
|
||||||
await saveIdentity(identity)
|
|
||||||
const identity2 = await getIdentity(identity.id)
|
|
||||||
expect(identity2).not.toBe(identity)
|
|
||||||
expect(identity2).toEqual(identity)
|
|
||||||
})
|
|
||||||
it('does not fail when not found', async () => {
|
|
||||||
const identity = await getIdentity('notfound')
|
|
||||||
expect(identity).toBe(undefined)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
})
|
|
||||||
@ -1,53 +0,0 @@
|
|||||||
import { open } from './open'
|
|
||||||
import { promisify } from './promisify'
|
|
||||||
import { exportKey, importKey } from '../crypto'
|
|
||||||
|
|
||||||
export interface Identity {
|
|
||||||
id: string
|
|
||||||
publicKey: CryptoKey
|
|
||||||
privateKey?: CryptoKey
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface StoredIdentity {
|
|
||||||
id: string
|
|
||||||
publicKey: JsonWebKey
|
|
||||||
privateKey?: JsonWebKey
|
|
||||||
}
|
|
||||||
|
|
||||||
const DB = 'PEERCALLS'
|
|
||||||
|
|
||||||
export async function getIdentity(id: string): Promise<Identity | undefined> {
|
|
||||||
const db = await open(DB, 1)
|
|
||||||
let stored: StoredIdentity | undefined
|
|
||||||
try {
|
|
||||||
const tx = db.transaction('identities', 'readonly')
|
|
||||||
const store = tx.objectStore('identities')
|
|
||||||
stored = await promisify(store.get(id))
|
|
||||||
} finally {
|
|
||||||
db.close()
|
|
||||||
}
|
|
||||||
|
|
||||||
return stored && {
|
|
||||||
id: stored.id,
|
|
||||||
privateKey: stored.privateKey && await importKey(stored.privateKey),
|
|
||||||
publicKey: await importKey(stored.publicKey),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function saveIdentity(identity: Identity): Promise<void> {
|
|
||||||
const stored = {
|
|
||||||
id: identity.id,
|
|
||||||
privateKey: identity.privateKey && await exportKey(identity.privateKey),
|
|
||||||
publicKey: await exportKey(identity.publicKey),
|
|
||||||
}
|
|
||||||
|
|
||||||
const db = await open(DB, 1)
|
|
||||||
try {
|
|
||||||
const tx = db.transaction('identities', 'readwrite')
|
|
||||||
const store = tx.objectStore('identities')
|
|
||||||
await promisify(store.put(stored))
|
|
||||||
await promisify(tx)
|
|
||||||
} finally {
|
|
||||||
db.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,3 +1,2 @@
|
|||||||
export { promisify } from './promisify'
|
export { promisify } from './promisify'
|
||||||
export { open } from './open'
|
export { open } from './open'
|
||||||
export * from './identities'
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user