Skip to content
This repository was archived by the owner on Mar 8, 2023. It is now read-only.

Commit 4120e4f

Browse files
committed
sign & verify
1 parent 03156bf commit 4120e4f

18 files changed

+782
-310
lines changed

dist/db/Message.d.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Actor } from './Actor';
22
import { Children } from "./Node";
33
export declare class Message {
44
static fromObject(obj: any): Message;
5-
static deserialize(str: string, from: Actor): Message;
5+
static deserialize(str: string, from: Actor): Promise<Message>;
66
serialize(): string;
77
}
88
export declare class Get implements Message {
@@ -15,7 +15,7 @@ export declare class Get implements Message {
1515
jsonStr?: string;
1616
checksum?: string;
1717
serialize(): string;
18-
static deserialize(obj: any, jsonStr: string, from: Actor): Get;
18+
static deserialize(obj: any, jsonStr: string, from: Actor): Promise<Get>;
1919
static fromObject(obj: any): Get;
2020
static new(nodeId: string, from: Actor, recipients?: string[], childKey?: string, jsonStr?: string, checksum?: string): Get;
2121
constructor(id: string, nodeId: string, from: Actor, recipients?: string[], childKey?: string, jsonStr?: string, checksum?: string);
@@ -33,7 +33,7 @@ export declare class Put implements Message {
3333
jsonStr?: string;
3434
checksum?: string;
3535
serialize(): string;
36-
static deserialize(obj: any, jsonStr: string, from: Actor): Put;
36+
static deserialize(obj: any, jsonStr: string, from: Actor): Promise<Put>;
3737
static fromObject(obj: any): Put;
3838
static new(updatedNodes: UpdatedNodes, from: Actor, inResponseTo?: string, recipients?: string[], jsonStr?: string, checksum?: string): Put;
3939
static newFromKv(key: string, children: Children, from: Actor): Put;

dist/iris.cjs.development.js

+237-92
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.cjs.development.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.cjs.production.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.cjs.production.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.esm.js

+237-92
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.esm.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.umd.development.js

+237-92
Large diffs are not rendered by default.

dist/iris.umd.development.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.umd.production.min.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/iris.umd.production.min.js.map

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/util.d.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
declare function gunOnceDefined(node: any): Promise<unknown>;
22
declare const _default: {
33
gunOnceDefined: typeof gunOnceDefined;
4-
getHash(str: string, format?: string): Promise<string | undefined>;
4+
getHash(data: any, format?: string): Promise<string | ArrayBuffer>;
55
capitalize(s: string): string;
66
generateName(): string;
77
base64ToHex(str: string): string;

src/Key.ts

+17-12
Original file line numberDiff line numberDiff line change
@@ -153,17 +153,14 @@ class Key {
153153

154154
static async sign(data: any, pair: any, cb?: Function, opt: any = {}) {
155155
if(undefined === data){ throw '`undefined` not allowed.' }
156-
if (typeof data === 'object') {
157-
data = JSON.stringify(data);
158-
}
156+
const text = JSON.stringify(data);
159157
var jwk = Key.keyToJwk(pair);
160-
console.log('signing with jwk', jwk);
161-
var hash = await util.getHash(data);
158+
var hash = await util.getHash(text, 'buffer') as Buffer;
162159
var sig = await window.crypto.subtle.importKey('jwk', jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ['sign'])
163160
.then((key) =>
164-
window.crypto.subtle.sign({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, new Uint8Array(hash as any))
161+
window.crypto.subtle.sign({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, hash)
165162
) // privateKey scope doesn't leak out from here!
166-
var r: any = {m: JSON.stringify(data), s: Buffer.from(sig).toString(opt.encode || 'base64')}
163+
var r: any = {m: text, s: Buffer.from(sig).toString(opt.encode || 'base64')}
167164
if(!opt.raw){ r = 'aSEA' + JSON.stringify(r) }
168165

169166
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
@@ -173,18 +170,26 @@ class Key {
173170
static async verify(data: any, pair: any, cb?: Function, opt: any = {}) {
174171
try {
175172
if (typeof data === 'string') {
176-
console.log('verifying string', data.slice(4));
177-
data = JSON.parse(data.slice(4));
173+
if (data.slice(0, 4) === 'aSEA') {
174+
data = JSON.parse(data.slice(4));
175+
} else {
176+
data = JSON.parse(data);
177+
}
178178
}
179179
var pub = pair.pub || pair;
180180
var jwk = Key.keyToJwk(pub);
181181
var key = await crypto.subtle.importKey('jwk', jwk, {name: 'ECDSA', namedCurve: 'P-256'}, false, ['verify']);
182-
var hash: any = await util.getHash(data.m);
182+
183+
var text = (typeof data.m === 'string')? data.m : JSON.stringify(data.m);
184+
let hash = await util.getHash(text, 'buffer') as Buffer;
183185
var buf, sig, isValid;
184-
buf = Buffer.from(data.s, opt.encode || 'base64'); // NEW DEFAULT!
186+
buf = Buffer.from(data.s, opt.encode || 'base64');
185187
sig = new Uint8Array(buf);
186-
isValid = await crypto.subtle.verify({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, sig, new Uint8Array(hash));
188+
isValid = await crypto.subtle.verify({name: 'ECDSA', hash: {name: 'SHA-256'}}, key, sig, hash);
187189
var r = isValid? JSON.parse(data.m) : undefined;
190+
if (r === undefined) {
191+
//console.log('invalid', data, pair, hash);
192+
}
188193

189194
if(cb){ try{ cb(r) }catch(e){console.log(e)} }
190195
return r;

src/db/Message.ts

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {Actor} from './Actor';
22
import {Children} from "./Node";
3+
import Key from "../Key";
34

45
export class Message {
56
// When Messages are sent over BroadcastChannel, class name is lost.
@@ -13,7 +14,7 @@ export class Message {
1314
}
1415
}
1516

16-
static deserialize(str: string, from: Actor): Message {
17+
static async deserialize(str: string, from: Actor): Promise<Message> {
1718
const obj = JSON.parse(str);
1819
if (obj.get) {
1920
return Get.deserialize(obj, str, from);
@@ -67,7 +68,7 @@ export class Get implements Message {
6768
return this.jsonStr;
6869
}
6970

70-
static deserialize(obj: any, jsonStr: string, from: Actor): Get {
71+
static async deserialize(obj: any, jsonStr: string, from: Actor): Promise<Get> {
7172
const id = obj['#'];
7273
let nodeId = obj.get['#']; // TODO add "global/" prefix, replace /^~/ with "user/"
7374
if (nodeId.startsWith('~')) {
@@ -136,7 +137,7 @@ export class Put implements Message {
136137
return JSON.stringify(obj);
137138
}
138139

139-
static deserialize(obj: any, jsonStr: string, from: Actor): Put {
140+
static async deserialize(obj: any, jsonStr: string, from: Actor): Promise<Put> {
140141
const id = obj['#'];
141142
const updatedNodes: UpdatedNodes = {};
142143
type SerializedChildren = {
@@ -145,10 +146,29 @@ export class Put implements Message {
145146
for (const [nodeId, c] of Object.entries(obj.put)) {
146147
const children = c as SerializedChildren;
147148
const node: any = {};
149+
const isUserSpace = nodeId.startsWith('~');
148150
for (const [childKey, childValue] of Object.entries(children)) {
149151
if (childKey === '_') {
150152
continue;
151153
}
154+
if (isUserSpace) {
155+
const user = nodeId.split('/')[0].slice(1);
156+
const signatureObj = JSON.parse(childValue);
157+
const timestamp = children['_']['>'][childKey];
158+
const value = signatureObj[':'];
159+
const signedObj = {
160+
"#": nodeId,
161+
".": childKey,
162+
":": value,
163+
">": timestamp
164+
};
165+
const signature = signatureObj['~'];
166+
const signedStr = JSON.stringify(signedObj);
167+
if (await Key.verify({s: signature, m: signedStr}, user) === undefined) {
168+
throw new Error(`invalid signature in ${nodeId} of ${signedStr}`);
169+
}
170+
}
171+
// TODO test hash space validity
152172
const updatedAt = children['_']['>'][childKey];
153173
node[childKey] = {
154174
value: childValue,

src/db/adapters/Websocket.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@ export default class Websocket extends Actor {
1818
this.sendQueue.forEach((message) => this.ws.send(message));
1919
this.sendQueue = [];
2020
}
21-
this.ws.onmessage = (event) => {
21+
this.ws.onmessage = async (event) => {
2222
try {
23-
const message = Message.deserialize(event.data, this);
23+
const message = await Message.deserialize(event.data, this);
2424
this.router.postMessage(message);
2525
} catch (e) {
26-
console.log('Failed to deserialize message', event.data, e);
26+
//console.log('Failed to deserialize message', event.data, e);
2727
}
2828
}
2929
this.ws.onclose = () => {

src/peers.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export default {
126126
},
127127

128128
isMixedContent(url: string) {
129+
if (!url) { return false; }
129130
return window.location.protocol === 'https:' && (url.indexOf('http:') === 0);
130131
},
131132

@@ -135,13 +136,14 @@ export default {
135136
const sample = _.sampleSize(
136137
Object.keys(
137138
_.pickBy(this.known, (peer: any, url: string) => {
138-
return url && !this.isMixedContent(url) && peer.enabled && !(util.isElectron && url === ELECTRON_GUN_URL);
139+
return !this.isMixedContent(url) && peer.enabled && !(util.isElectron && url === ELECTRON_GUN_URL);
139140
})
140141
), sampleSize
141142
);
142143
if (sample && connectToLocalElectron) {
143144
sample.push(ELECTRON_GUN_URL);
144145
}
146+
console.log('sample', sample, JSON.stringify(this.known));
145147
return sample;
146148
},
147149

src/util.ts

+13-4
Original file line numberDiff line numberDiff line change
@@ -1850,13 +1850,22 @@ const adjectives = [
18501850

18511851
export default {
18521852
gunOnceDefined,
1853-
async getHash (str: string, format = `base64`) {
1854-
if (!str) {
1855-
return undefined;
1853+
async getHash (data: any, format = `base64`) {
1854+
if (data === undefined) {
1855+
throw new Error('getHash data was undefined');
18561856
}
1857+
if (typeof data !== 'string') {
1858+
data = JSON.stringify(data);
1859+
}
1860+
18571861
const encoder = new TextEncoder();
1858-
const data = encoder.encode(str);
1862+
data = encoder.encode(data);
18591863
const buffer = await crypto.subtle.digest('SHA-256', data);
1864+
1865+
if (format === 'buffer') {
1866+
return buffer;
1867+
}
1868+
18601869
const hash = this.arrayBufferToBase64(buffer);
18611870
if (format === `hex`) {
18621871
return this.base64ToHex(hash);

test/blah.test.js

+1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ describe('iris', () => {
3737
const key = await iris.Key.generate();
3838
const msg = 'hello';
3939
const signedMsg = await iris.Key.sign(msg, key);
40+
console.log('signedMsg', signedMsg);
4041
const verified = await iris.Key.verify(signedMsg, key);
4142
expect(verified).toBe(msg);
4243
});

0 commit comments

Comments
 (0)