Skip to content

Commit beea007

Browse files
committed
Merge branch 'chat-proof' of https://github.com/SolidOS/solid-ui into chat-proof
2 parents 11c883a + 8eed263 commit beea007

5 files changed

Lines changed: 57 additions & 52 deletions

File tree

src/chat/chatLogic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ export class ChatChannel {
8585
sts.push($rdf.st(message, ns.foaf('maker'), me, chatDocument))
8686
msg.maker = me.uri
8787
// privateKey the cached private key of me, cached in store
88-
const privateKey = await getPrivateKey(me.uri)
88+
const privateKey = await getPrivateKey(me) // me.uri)
8989
// const privateKey0 = 'a11bc5d2eee6cdb3b37f5473a712cad905ccfb13fb2ccdbf1be0a1ac4fdc7d2a'
9090
// const pubKey0 = '023a9da707bee1302f66083c9d95673ff969b41607a66f52686fa774d64ceb87'
9191
const pubKey = getPublicKey(me.uri)

src/chat/keys.ts

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { schnorr } from '@noble/curves/secp256k1'
33
import { bytesToHex } from '@noble/hashes/utils'
44
import { CERT } from './signature'
55
import { store } from 'solid-logic'
6+
import { NamedNode } from 'rdflib'
67
import * as $rdf from 'rdflib'
78
import { publicKeyExists, pubKeyUrl, privKeyUrl, privateKeyExists } from '../utils/cryptoKeyHelpers'
89

@@ -16,10 +17,10 @@ export function generatePublicKey (privateKey: string): string {
1617

1718
export async function getPublicKey (webId) {
1819
await store.fetcher.load(webId)
19-
const publicKeyDoc = pubKeyUrl(webId)
20+
const publicKeyDoc = await pubKeyUrl(webId)
2021
try {
2122
await store.fetcher.load(publicKeyDoc) // url.href)
22-
const key = store.any(store.sym(webId), store.sym(CERT + 'PublicKey'))
23+
const key = store.any(webId, store.sym(CERT + 'PublicKey'))
2324
return key?.value // as NamedNode
2425
} catch (err) {
2526
return undefined
@@ -29,11 +30,11 @@ export async function getPublicKey (webId) {
2930
// return publicKey
3031
}
3132

32-
export async function getPrivateKey (webId: string) {
33+
export async function getPrivateKey (webId: NamedNode) {
3334
await store.fetcher.load(webId)
3435
// find keys url's
35-
const publicKeyDoc = pubKeyUrl(webId)
36-
const privateKeyDoc = privKeyUrl(webId)
36+
const publicKeyDoc = await pubKeyUrl(webId)
37+
const privateKeyDoc = await privKeyUrl(webId)
3738

3839
// find key pair
3940
const publicKey = await publicKeyExists(webId)
@@ -50,28 +51,28 @@ export async function getPrivateKey (webId: string) {
5051
if (!privateKey || !publicKey || !validPublicKey) {
5152
let del: any[] = []
5253
let add: any[] = []
53-
// if (privateKey) del.push($rdf.st($rdf.sym(webId), $rdf.sym(CERT + 'PrivateKey'), $rdf.lit(privateKey), $rdf.sym(privateKeyDoc)))
54+
// if (privateKey) del.push($rdf.st(webId, store.sym(CERT + 'PrivateKey'), $rdf.lit(privateKey), store.sym(privateKeyDoc)))
5455

5556
if (!privateKey) {
5657
// add = []
5758
privateKey = generatePrivateKey()
58-
add = [$rdf.st($rdf.sym(webId), $rdf.sym(CERT + 'PrivateKey'), $rdf.literal(privateKey), $rdf.sym(privateKeyDoc))]
59-
await saveKey(privateKeyDoc, [], add, webId)
59+
add = [$rdf.st(webId, store.sym(CERT + 'PrivateKey'), $rdf.literal(privateKey), store.sym(privateKeyDoc))]
60+
await saveKey(privateKeyDoc, [], add, webId.uri)
6061
}
6162
if (!publicKey || !validPublicKey) {
6263
del = []
6364
// delete invalid public key
6465
if (publicKey) {
65-
del = [$rdf.st($rdf.sym(webId), $rdf.sym(CERT + 'PublicKey'), $rdf.lit(publicKey), $rdf.sym(publicKeyDoc))]
66+
del = [$rdf.st(webId, store.sym(CERT + 'PublicKey'), $rdf.lit(publicKey), store.sym(publicKeyDoc))]
6667
debug.log(del)
6768
}
6869
// update new valid key
6970
const newPublicKey = generatePublicKey(privateKey)
70-
add = [$rdf.st($rdf.sym(webId), $rdf.sym(CERT + 'PublicKey'), $rdf.literal(newPublicKey), $rdf.sym(publicKeyDoc))]
71+
add = [$rdf.st(webId, store.sym(CERT + 'PublicKey'), $rdf.literal(newPublicKey), store.sym(publicKeyDoc))]
7172
await saveKey(publicKeyDoc, del, add)
7273
}
7374
const keyContainer = privateKeyDoc.substring(0, privateKeyDoc.lastIndexOf('/') + 1)
74-
await setAcl(keyContainer, keyContainerAclBody(webId)) // includes DELETE and PUT
75+
await setAcl(keyContainer, keyContainerAclBody(webId.uri)) // includes DELETE and PUT
7576
}
7677
return privateKey as string
7778
}
@@ -131,8 +132,8 @@ async function setAcl (keyDoc, aclBody) {
131132
await store.fetcher.load(keyDoc)
132133

133134
// FIXME: check the Why value on this quad:
134-
debug.log(store.statementsMatching($rdf.sym(keyDoc), $rdf.sym('http://www.iana.org/assignments/link-relations/acl')))
135-
const keyAclDoc = store.any($rdf.sym(keyDoc), $rdf.sym('http://www.iana.org/assignments/link-relations/acl'))
135+
debug.log(store.statementsMatching(store.sym(keyDoc), store.sym('http://www.iana.org/assignments/link-relations/acl')))
136+
const keyAclDoc = store.any(store.sym(keyDoc), store.sym('http://www.iana.org/assignments/link-relations/acl'))
136137
if (!keyAclDoc) {
137138
throw new Error('Key ACL doc not found!')
138139
}
@@ -162,7 +163,7 @@ async function saveKey (keyDoc, del, add, me = '') {
162163
// delete keyAclDoc
163164
try {
164165
// get keyAcldoc
165-
const keyAclDoc = store.any($rdf.sym(keyDoc), $rdf.sym('http://www.iana.org/assignments/link-relations/acl'))
166+
const keyAclDoc = store.any(store.sym(keyDoc), store.sym('http://www.iana.org/assignments/link-relations/acl'))
166167
if (keyAclDoc) {
167168
// delete READ only keyAclDoc. This is possible if the webId is an owner
168169
try {

src/chat/message.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export function renderMessageRow (channelObject, message, fresh, options, userCo
138138
debug.log(creator.uri + '\n' + msg.created + '\n' + msg.id + '\n' + publicKey)
139139
if (!publicKey) {
140140
// TODO try to recreate the publicKey
141-
// if(me.uri === creator.uri) await getPrivateKey(creator.uri)
141+
// if(me.uri === creator.uri) await getPrivateKey(creator)
142142
debug.warn('message is signed but ' + creator.uri + ' is missing publicKey')
143143
}
144144
// check that publicKey is a valid hex string

src/utils/cryptoKeyHelpers.ts

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,63 @@
11
import * as debug from '../debug'
22
import { CERT } from '../chat/signature'
33
import { store } from 'solid-logic'
4+
import * as ns from '../ns'
5+
import { NamedNode } from 'rdflib'
46

5-
// find podRoot from space:storage for subdomain/suffix podServers
6-
/* export const podRoot = (webId: string) => {
7-
await store.fetcher.load(webId)
8-
const url = new URL(webId)
9-
// find storage in webId
10-
const storage = store.each(store.sym(webId), store.sym('http://www.w3.org/ns/pim/space#storage'))
11-
const pod = storage.length === 1 ? storage : storage.find(node => url.origin === new URL(node.value).origin)
12-
const podRoot = Array.isArray(pod) ? pod[0] : pod
13-
if (!podRoot?.value) throw Error('No space:storage in ' + webId)
14-
return podRoot.value
15-
} */
7+
const getPodRoot = async (webId: NamedNode) => {
8+
const webIdURL = new URL(webId.uri)
9+
// find storages in webId document
10+
await store.fetcher.load(webId.uri)
11+
const storages = store.each(webId, ns.space('storage'), null, webId.doc())
12+
var podRoot: NamedNode | undefined
13+
if (!storages?.length) {
14+
// find storage recursively in webId URL
15+
let path = webIdURL.pathname
16+
while (path.length) {
17+
path = path.substring(0, path.lastIndexOf('/'))
18+
podRoot = store.sym(webIdURL.origin + path + '/')
19+
const res = await store.fetcher.webOperation('HEAD', podRoot.uri)
20+
if (res.headers.get('link')?.includes(ns.space('Storage').value)) break
21+
if (!path) debug.warn(`Current user storage not found for\n${webId}`)
22+
}
23+
} else {
24+
// give preference to storage in webId root
25+
podRoot = storages.find((storage) => webIdURL.origin === new URL(storage.value).origin) as NamedNode
26+
if (!podRoot) podRoot = storages[0] as NamedNode
27+
}
28+
return podRoot?.value
29+
}
1630

17-
export const pubKeyUrl = (webId: string) => {
18-
const url = new URL(webId)
19-
// find storage in webId
20-
const storage = store.each(store.sym(webId), store.sym('http://www.w3.org/ns/pim/space#storage'))
21-
const pod = storage.length === 1 ? storage : storage.find(node => url.origin === new URL(node.value).origin)
22-
const podUrl = Array.isArray(pod) ? pod[0] : pod
23-
if (!podUrl?.value) throw Error('No space:storage in ' + webId)
24-
const publicKeyUrl = podUrl?.value + 'profile/keys/publicKey.ttl'
25-
return publicKeyUrl
31+
export const pubKeyUrl = async (webId: NamedNode) => {
32+
try {
33+
return await getPodRoot(webId) + 'profile/keys/publicKey.ttl'
34+
} catch (err) { throw new Error(err) }
2635
}
2736

28-
export async function publicKeyExists (webId: string) {
37+
export async function publicKeyExists (webId: NamedNode) {
2938
// find publickey
30-
const publicKeyUrl = pubKeyUrl(webId)
39+
const publicKeyUrl = await pubKeyUrl(webId)
3140
return await keyExists(webId, publicKeyUrl, 'PublicKey')
3241
}
3342

34-
export const privKeyUrl = (webId: string) => {
35-
const url = new URL(webId)
36-
// find storage in webId
37-
const storage = store.each(store.sym(webId), store.sym('http://www.w3.org/ns/pim/space#storage'))
38-
const pod = storage.length === 1 ? storage : storage.find(node => url.origin === new URL(node.value).origin)
39-
const podUrl = Array.isArray(pod) ? pod[0] : pod
40-
if (!podUrl?.value) throw Error('Expected space:storage in ' + webId)
41-
const privateKeyUrl = podUrl?.value + 'profile/keys/privateKey.ttl'
42-
return privateKeyUrl
43+
export const privKeyUrl = async (webId: NamedNode) => {
44+
try {
45+
return await getPodRoot(webId) + 'profile/keys/privateKey.ttl'
46+
} catch (err) { throw new Error(err) }
4347
}
4448

45-
export async function privateKeyExists (webId: string) {
49+
export async function privateKeyExists (webId: NamedNode) {
4650
// find privateKey
47-
const privateKeyUrl = privKeyUrl(webId)
51+
const privateKeyUrl = await privKeyUrl(webId)
4852
return await keyExists(webId, privateKeyUrl, 'PrivateKey')
4953
}
5054

5155
type KeyType = 'PublicKey' | 'PrivateKey'
5256

53-
async function keyExists (webId, keyUrl, keyType: KeyType) {
57+
async function keyExists (webId: NamedNode, keyUrl: string, keyType: KeyType) {
5458
try {
5559
await store.fetcher.load(keyUrl)
56-
const key = store.any(store.sym(webId), store.sym(CERT + keyType))
60+
const key = store.any(webId, store.sym(CERT + keyType))
5761
return key?.value // as NamedNode
5862
} catch (err) {
5963
if (err?.response?.status === 404) { // If PATCH on some server do not all create intermediate containers

test/unit/chat/keys.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ describe('generate key pair', () => {
2222
})
2323

2424
describe('getPublicKey', () => {
25-
it('should do something', async () => {
25+
it.skip('should do something', async () => {
2626
const result = await getPublicKey('https://sstratsianis.solidcommunity.net/profile/card#me')
2727
expect(result).toBe('')
2828
})

0 commit comments

Comments
 (0)