Skip to content

Commit

Permalink
Merge pull request #115 from DeepDoge/master
Browse files Browse the repository at this point in the history
Bug Fixes
  • Loading branch information
kodxana authored May 1, 2022
2 parents a27d5a2 + c2f894e commit 6b8f193
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 74 deletions.
125 changes: 60 additions & 65 deletions src/common/crypto.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { getExtensionSettingsAsync } from "./settings"
import { getExtensionSettingsAsync, ytUrlResolversSettings } from "./settings"
import { setSetting } from "./useSettings"
import path from 'path'

async function generateKeys() {
const keys = await window.crypto.subtle.generateKey(
{
name: "RSASSA-PKCS1-v1_5",
// Consider using a 4096-bit key for systems that require long-term security
modulusLength: 2048,
modulusLength: 384,
publicExponent: new Uint8Array([1, 0, 1]),
hash: "SHA-256",
hash: "SHA-1",
},
true,
["sign", "verify"]
Expand All @@ -28,22 +29,26 @@ async function exportPrivateKey(key: CryptoKey) {
return Buffer.from(exported).toString('base64')
}

const publicKeyPrefix = `MEwwDQYJKoZIhvcNAQEBBQADOwAwOAIxA`
const publicKeySuffix = `IDAQAB` //`wIDAQAB` `WIDAQAB`
const publicKeyLength = 65
async function exportPublicKey(key: CryptoKey) {
const exported = await window.crypto.subtle.exportKey(
"spki",
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) {

return window.crypto.subtle.importKey(
"pkcs8",
Buffer.from(base64, 'base64'),
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256",
hash: "SHA-1",
},
true,
["sign"]
Expand All @@ -54,7 +59,7 @@ export async function sign(data: string, privateKey: string) {
return Buffer.from(await window.crypto.subtle.sign(
{ name: "RSASSA-PKCS1-v1_5" },
await importPrivateKey(privateKey),
Buffer.from(data)
await crypto.subtle.digest({ name: 'SHA-1' }, Buffer.from(data))
)).toString('base64')
}

Expand All @@ -63,6 +68,33 @@ export function resetProfileSettings() {
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) {
let { publicKey, privateKey } = await getExtensionSettingsAsync()

Expand All @@ -74,80 +106,43 @@ export async function generateProfileAndSetNickname(overwrite = false) {
alert("Invalid nickname")
}

if (overwrite || !privateKey || !publicKey) {
resetProfileSettings()
await generateKeys().then((keys) => {
publicKey = keys.publicKey
privateKey = keys.privateKey
})
}

const url = new URL('https://finder.madiator.com/api/v1/profile')
url.searchParams.set('data', JSON.stringify({ nickname }))
url.searchParams.set('keys', JSON.stringify({
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)
try {
if (overwrite || !privateKey || !publicKey) {
resetProfileSettings()
await generateKeys().then((keys) => {
publicKey = keys.publicKey
privateKey = keys.privateKey
})
setSetting('publicKey', publicKey)
setSetting('privateKey', privateKey)
}
await apiRequest('POST', '/profile', { 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() {
try {
if (!confirm("This will purge all of your online and offline profile data.\nStill wanna continue?")) return
const settings = await getExtensionSettingsAsync()

if (!settings.privateKey || !settings.publicKey)
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)
await apiRequest('POST', '/profile/purge', {})
resetProfileSettings()
alert(`Your profile has been purged`)
} catch (error: any) {
alert(error.message)
}
}

export async function getProfile() {
try {
const settings = await getExtensionSettingsAsync()

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)
}
let { publicKey, privateKey } = await getExtensionSettingsAsync()
return (await apiRequest('GET', '/profile', { publicKey })) as { nickname: string, score: number, publickKey: string }
}

export function friendlyPublicKey(publicKey: string | null) {
// 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) {
Expand Down Expand Up @@ -177,7 +172,7 @@ async function readFile() {
const reader = new FileReader()

reader.addEventListener('load', () => resolve(reader.result?.toString() ?? null))
reader.readAsBinaryString(myFile)
reader.readAsText(myFile)
})
})
}
Expand Down
11 changes: 8 additions & 3 deletions src/common/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,17 @@ export const getYtUrlResolversSettingsEntiries = () => Object.entries(ytUrlResol
export const ytUrlResolversSettings = {
odyseeApi: ytUrlResolver({
name: "Odysee",
href: "https://api.odysee.com/yt/resolve",
href: "https://api.odysee.com/yt",
signRequest: false
}),
madiatorFinder: ytUrlResolver({
name: "Madiator Finder",
href: "https://finder.madiator.com/api/v1/resolve",
href: "https://finder.madiator.com/api/v1",
signRequest: true
})
}),
/* madiatorFinderLocal: ytUrlResolver({
name: "Madiator Finder Local",
href: "http://127.0.0.1:3001/api/v1",
signRequest: true
}) */
}
2 changes: 2 additions & 0 deletions src/common/yt/urlResolve.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { chunk } from "lodash"
import { sign } from "../crypto"
import { getExtensionSettingsAsync, ytUrlResolversSettings } from "../settings"
import { LbryPathnameCache } from "./urlCache"
import path from "path"

const QUERY_CHUNK_SIZE = 100

Expand Down Expand Up @@ -41,6 +42,7 @@ export async function resolveById(params: Paramaters, progressCallback?: (progre
if (params.length === 0) return results

const url = new URL(`${urlResolverSetting.href}`)
url.pathname = path.join(url.pathname, '/resolve')
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(','))
if (urlResolverSetting.signRequest && publicKey && privateKey)
Expand Down
7 changes: 6 additions & 1 deletion src/popup/popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,12 @@ function WatchOnLbryPopup(params: { profile: Awaited<ReturnType<typeof getProfil
}
</section>
</header>
: <header><a className='button filled' onClick={() => updateRoute('profile')} href="#profile">Your Profile</a>
: <header>
{
popupRoute === 'profile'
? <a onClick={() => updateRoute('')} className="button filled">⇐ Back</a>
: <a className='button filled' onClick={() => updateRoute('profile')} href="#profile">Your Profile</a>
}
</header>
}
{
Expand Down
2 changes: 1 addition & 1 deletion src/scripts/background.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ chrome.runtime.onMessage.addListener(({ json }, sender, sendResponse) => {
return true
})

chrome.tabs.onUpdated.addListener((tabId, changeInfo) => changeInfo.url && chrome.tabs.sendMessage(tabId, {}))
chrome.tabs.onUpdated.addListener((tabId, changeInfo) => changeInfo.status === 'complete' && chrome.tabs.sendMessage(tabId, { message: 'url-changed' }))
10 changes: 7 additions & 3 deletions src/scripts/storageSetup.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { DEFAULT_SETTINGS, ExtensionSettings, getExtensionSettingsAsync } from '../common/settings'
import { DEFAULT_SETTINGS, ExtensionSettings, getExtensionSettingsAsync, sourcePlatfromSettings, targetPlatformSettings, ytUrlResolversSettings } from '../common/settings'
import { setSetting } from '../common/useSettings'

/** Reset settings to default value and update the browser badge text */
async function initSettings() {
const settings = await getExtensionSettingsAsync()
let settings = await getExtensionSettingsAsync()

// get all the values that aren't set and use them as a change set
const invalidEntries = (Object.entries(DEFAULT_SETTINGS) as Array<[keyof ExtensionSettings, ExtensionSettings[keyof ExtensionSettings]]>)
Expand All @@ -11,10 +12,13 @@ async function initSettings() {
// fix our local var and set it in storage for later
if (invalidEntries.length > 0) {
const changeSet = Object.fromEntries(invalidEntries)
Object.assign(settings, changeSet)
chrome.storage.local.set(changeSet)
settings = await getExtensionSettingsAsync()
}

if (!Object.keys(targetPlatformSettings).includes(settings.targetPlatform)) setSetting('targetPlatform', DEFAULT_SETTINGS.targetPlatform)
if (!Object.keys(ytUrlResolversSettings).includes(settings.urlResolver)) setSetting('urlResolver', DEFAULT_SETTINGS.urlResolver)

chrome.browserAction.setBadgeText({ text: settings.redirect ? 'ON' : 'OFF' })
}

Expand Down
2 changes: 1 addition & 1 deletion src/scripts/ytContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ async function requestResolveById(...params: Parameters<typeof resolveById>): Re
* history.pushState changes from a content script
*/
// Listen URL Change
chrome.runtime.onMessage.addListener(() => updater())
chrome.runtime.onMessage.addListener(({ message }, sender) => message === 'url-changed' && updater())

async function getTargetByURL(url: URL) {
if (url.pathname === '/watch' && url.searchParams.has('v')) {
Expand Down

0 comments on commit 6b8f193

Please sign in to comment.