🍣 crypto changes

This commit is contained in:
Shiba 2022-04-30 23:25:30 +00:00
parent deed10423a
commit f86affc093
3 changed files with 68 additions and 67 deletions

View file

@ -1,14 +1,15 @@
import { getExtensionSettingsAsync } from "./settings" import { getExtensionSettingsAsync, ytUrlResolversSettings } from "./settings"
import { setSetting } from "./useSettings" import { setSetting } from "./useSettings"
import path from 'path'
async function generateKeys() { async function generateKeys() {
const keys = await window.crypto.subtle.generateKey( const keys = await window.crypto.subtle.generateKey(
{ {
name: "RSASSA-PKCS1-v1_5", name: "RSASSA-PKCS1-v1_5",
// Consider using a 4096-bit key for systems that require long-term security // Consider using a 4096-bit key for systems that require long-term security
modulusLength: 2048, modulusLength: 384,
publicExponent: new Uint8Array([1, 0, 1]), publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256", hash: "SHA-1",
}, },
true, true,
["sign", "verify"] ["sign", "verify"]
@ -28,22 +29,26 @@ async function exportPrivateKey(key: CryptoKey) {
return Buffer.from(exported).toString('base64') return Buffer.from(exported).toString('base64')
} }
const publicKeyPrefix = `MEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxA`
const publicKeySuffix = `IDAQAB` //`wIDAQAB` `WIDAQAB`
const publicKeyLength = 65
async function exportPublicKey(key: CryptoKey) { async function exportPublicKey(key: CryptoKey) {
const exported = await window.crypto.subtle.exportKey( const exported = await window.crypto.subtle.exportKey(
"spki", "spki",
key key
) )
return Buffer.from(exported).toString('base64') const publicKey = Buffer.from(exported).toString('base64')
console.log(publicKey)
return publicKey.substring(publicKeyPrefix.length, publicKeyPrefix.length + publicKeyLength)
} }
function importPrivateKey(base64: string) { function importPrivateKey(base64: string) {
return window.crypto.subtle.importKey( return window.crypto.subtle.importKey(
"pkcs8", "pkcs8",
Buffer.from(base64, 'base64'), Buffer.from(base64, 'base64'),
{ {
name: "RSASSA-PKCS1-v1_5", name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256", hash: "SHA-1",
}, },
true, true,
["sign"] ["sign"]
@ -54,7 +59,7 @@ export async function sign(data: string, privateKey: string) {
return Buffer.from(await window.crypto.subtle.sign( return Buffer.from(await window.crypto.subtle.sign(
{ name: "RSASSA-PKCS1-v1_5" }, { name: "RSASSA-PKCS1-v1_5" },
await importPrivateKey(privateKey), await importPrivateKey(privateKey),
Buffer.from(data) await crypto.subtle.digest({ name: 'SHA-1' }, Buffer.from(data))
)).toString('base64') )).toString('base64')
} }
@ -63,6 +68,33 @@ export function resetProfileSettings() {
setSetting('privateKey', null) setSetting('privateKey', null)
} }
async function apiRequest<T extends object>(method: 'GET' | 'POST', pathname: string, data: T) {
const settings = await getExtensionSettingsAsync()
/* const urlResolverSettings = ytUrlResolversSettings[settings.urlResolver]
if (!urlResolverSettings.signRequest) throw new Error() */
console.log(ytUrlResolversSettings)
const url = new URL(ytUrlResolversSettings.madiatorFinder.href/* urlResolverSettings.href */)
console.log(url)
url.pathname = path.join(url.pathname, pathname)
url.searchParams.set('data', JSON.stringify(data))
if (true/* requiresSignature */) {
if (!settings.privateKey || !settings.publicKey)
throw new Error('There is no profile.')
url.searchParams.set('keys', JSON.stringify({
signature: await sign(url.searchParams.toString(), settings.privateKey!),
publicKey: settings.publicKey
}))
}
const respond = await fetch(url.href, { method })
if (respond.ok) return respond.json()
throw new Error((await respond.json()).message)
}
export async function generateProfileAndSetNickname(overwrite = false) { export async function generateProfileAndSetNickname(overwrite = false) {
let { publicKey, privateKey } = await getExtensionSettingsAsync() let { publicKey, privateKey } = await getExtensionSettingsAsync()
@ -74,80 +106,43 @@ export async function generateProfileAndSetNickname(overwrite = false) {
alert("Invalid nickname") alert("Invalid nickname")
} }
if (overwrite || !privateKey || !publicKey) { try {
resetProfileSettings() if (overwrite || !privateKey || !publicKey) {
await generateKeys().then((keys) => { resetProfileSettings()
publicKey = keys.publicKey await generateKeys().then((keys) => {
privateKey = keys.privateKey publicKey = keys.publicKey
}) privateKey = keys.privateKey
} })
setSetting('publicKey', publicKey)
const url = new URL('https://finder.madiator.com/api/v1/profile') setSetting('privateKey', privateKey)
url.searchParams.set('data', JSON.stringify({ nickname })) }
url.searchParams.set('keys', JSON.stringify({ await apiRequest('POST', '/profile', { nickname })
signature: await sign(url.searchParams.toString(), privateKey!),
publicKey
}))
const respond = await fetch(url.href, { method: "POST" })
if (respond.ok) {
setSetting('publicKey', publicKey)
setSetting('privateKey', privateKey)
alert(`Your nickname has been set to ${nickname}`) alert(`Your nickname has been set to ${nickname}`)
} catch (error: any) {
resetProfileSettings()
alert(error.message)
} }
else alert((await respond.json()).message)
} }
export async function purgeProfile() { export async function purgeProfile() {
try { try {
if (!confirm("This will purge all of your online and offline profile data.\nStill wanna continue?")) return if (!confirm("This will purge all of your online and offline profile data.\nStill wanna continue?")) return
const settings = await getExtensionSettingsAsync() await apiRequest('POST', '/profile/purge', {})
resetProfileSettings()
if (!settings.privateKey || !settings.publicKey) alert(`Your profile has been purged`)
throw new Error('There is no profile to be purged.')
const url = new URL('https://finder.madiator.com/api/v1/profile/purge')
url.searchParams.set('keys', JSON.stringify({
signature: await sign(url.searchParams.toString(), settings.privateKey!),
publicKey: settings.publicKey
}))
const respond = await fetch(url.href, { method: "POST" })
if (respond.ok) {
resetProfileSettings()
alert(`Your profile has been purged`)
}
else throw new Error((await respond.json()).message)
} catch (error: any) { } catch (error: any) {
alert(error.message) alert(error.message)
} }
} }
export async function getProfile() { export async function getProfile() {
try { let { publicKey, privateKey } = await getExtensionSettingsAsync()
const settings = await getExtensionSettingsAsync() return (await apiRequest('GET', '/profile', { publicKey })) as { nickname: string, score: number, publickKey: string }
if (!settings.privateKey || !settings.publicKey)
throw new Error('There is no profile.')
const url = new URL('https://finder.madiator.com/api/v1/profile')
url.searchParams.set('data', JSON.stringify({ publicKey: settings.publicKey }))
url.searchParams.set('keys', JSON.stringify({
signature: await sign(url.searchParams.toString(), settings.privateKey!),
publicKey: settings.publicKey
}))
const respond = await fetch(url.href, { method: "GET" })
if (respond.ok) {
const profile = await respond.json() as { nickname: string, score: number, publickKey: string }
return profile
}
else throw new Error((await respond.json()).message)
} catch (error: any) {
console.error(error)
}
} }
export function friendlyPublicKey(publicKey: string | null) { export function friendlyPublicKey(publicKey: string | null) {
// This is copy paste of Madiator Finder's friendly public key // This is copy paste of Madiator Finder's friendly public key
return publicKey?.substring(publicKey.length - 64, publicKey.length - 32) return `${publicKey?.substring(0, 32)}...`
} }
function download(data: string, filename: string, type: string) { function download(data: string, filename: string, type: string) {

View file

@ -118,12 +118,17 @@ export const getYtUrlResolversSettingsEntiries = () => Object.entries(ytUrlResol
export const ytUrlResolversSettings = { export const ytUrlResolversSettings = {
odyseeApi: ytUrlResolver({ odyseeApi: ytUrlResolver({
name: "Odysee", name: "Odysee",
href: "https://api.odysee.com/yt/resolve", href: "https://api.odysee.com/yt",
signRequest: false signRequest: false
}), }),
madiatorFinder: ytUrlResolver({ madiatorFinder: ytUrlResolver({
name: "Madiator Finder", name: "Madiator Finder",
href: "https://finder.madiator.com/api/v1/resolve", href: "https://finder.madiator.com/api/v1",
signRequest: true signRequest: true
}) }),
/* madiatorFinderLocal: ytUrlResolver({
name: "Madiator Finder Local",
href: "http://127.0.0.1:3001/api/v1",
signRequest: true
}) */
} }

View file

@ -41,6 +41,7 @@ export async function resolveById(params: Paramaters, progressCallback?: (progre
if (params.length === 0) return results if (params.length === 0) return results
const url = new URL(`${urlResolverSetting.href}`) const url = new URL(`${urlResolverSetting.href}`)
url.pathname = '/resolve'
url.searchParams.set('video_ids', params.filter((item) => item.type === 'video').map((item) => item.id).join(',')) url.searchParams.set('video_ids', params.filter((item) => item.type === 'video').map((item) => item.id).join(','))
url.searchParams.set('channel_ids', params.filter((item) => item.type === 'channel').map((item) => item.id).join(',')) url.searchParams.set('channel_ids', params.filter((item) => item.type === 'channel').map((item) => item.id).join(','))
if (urlResolverSetting.signRequest && publicKey && privateKey) if (urlResolverSetting.signRequest && publicKey && privateKey)