@@ -336,54 +335,54 @@ export function PreviewPage(props: PreviewPageProps) {
{/* HERO */}
- {verifiedData.type === 'community' && (
+ {data.type === 'community' && (
)}
- {verifiedData.type === 'channel' && (
+ {data.type === 'channel' && (
)}
- {verifiedData.type === 'profile' && (
+ {data.type === 'profile' && (
)}
- {verifiedData.type === 'channel' && '#'}
- {verifiedData.info.displayName}
+ {data.type === 'channel' && '#'}
+ {data.info.displayName}
- {verifiedData.info.description}
+ {data.info.description}
- {verifiedData.type === 'community' && (
+ {data.type === 'community' && (
<>
- {formatNumber(verifiedData.info.membersCount)}
+ {formatNumber(data.info.membersCount)}
- {verifiedData.info.tags?.length > 0 && (
+ {data.info.tags?.length > 0 && (
- {verifiedData.info.tags.map(tag => (
+ {data.info.tags.map(tag => (
)}
- {verifiedData.type === 'channel' && (
+ {data.type === 'channel' && (
Channel in
@@ -403,18 +402,18 @@ export function PreviewPage(props: PreviewPageProps) {
)}
- {verifiedData.type === 'profile' && (
+ {data.type === 'profile' && (
- {verifiedData.info.emojiHash}
+ {data.info.emojiHash}
)}
@@ -497,9 +496,7 @@ export function PreviewPage(props: PreviewPageProps) {
!bannerURL
? {
backgroundColor:
- 'color' in verifiedData.info
- ? verifiedData.info.color
- : neutral[100],
+ 'color' in data.info ? data.info.color : neutral[100],
}
: undefined
}
@@ -527,14 +524,14 @@ const formatNumber = (n: number) => {
return formatter.format(n)
}
-const getGradientStyles = (data: VerifiedData): CSSProperties => {
+const getGradientStyles = (data: Data): CSSProperties => {
return {
// @ts-expect-error CSSProperties do not handle inline CSS variables
'--gradient-color': 'color' in data.info ? data.info.color : neutral[100],
}
}
-const getAvatarURL = (data: VerifiedData): string | undefined => {
+const getAvatarURL = (data: Data): string | undefined => {
let avatar: Uint8Array | undefined
switch (data.type) {
case 'community':
@@ -560,7 +557,7 @@ const getAvatarURL = (data: VerifiedData): string | undefined => {
return url
}
-const getBannerURL = (data: VerifiedData): string | undefined => {
+const getBannerURL = (data: Data): string | undefined => {
let banner: Uint8Array | undefined
switch (data.type) {
case 'community':
diff --git a/apps/website/src/consts/error-codes.ts b/apps/website/src/consts/error-codes.ts
index e0ab1eca..834df6e8 100644
--- a/apps/website/src/consts/error-codes.ts
+++ b/apps/website/src/consts/error-codes.ts
@@ -1,6 +1,5 @@
export const ERROR_CODES = {
NOT_FOUND: 404,
INTERNAL_SERVER_ERROR: 500,
- UNVERIFIED_CONTENT: 600,
INVALID_PUBLIC_KEY: 601,
}
diff --git a/apps/website/src/hooks/use-url-data.ts b/apps/website/src/hooks/use-url-data.ts
index f8e7ae6e..296f2e10 100644
--- a/apps/website/src/hooks/use-url-data.ts
+++ b/apps/website/src/hooks/use-url-data.ts
@@ -7,13 +7,12 @@ import {
indicesToTags,
publicKeyToColorHash,
publicKeyToEmojiHash,
- verifyEncodedURLData,
+ recoverPublicKeyFromEncodedURLData,
} from '@status-im/js'
-import { decodeVerificationURLHash } from '@status-im/js/encode-url-hash'
import { ERROR_CODES } from '@/consts/error-codes'
-import type { VerifiedData } from '@/components/preview-page'
+import type { Data } from '@/components/preview-page'
import type { ChannelInfo, CommunityInfo, UserInfo } from '@status-im/js'
import type {
decodeChannelURLData,
@@ -23,17 +22,17 @@ import type {
export const useURLData = (
type: 'community' | 'channel' | 'profile',
- unverifiedDecodedData:
+ decodedData:
| ReturnType
| ReturnType
| ReturnType
| undefined
| null,
- unverifiedEncodedData: string | undefined | null
+ encodedData: string | undefined | null
) => {
const [publicKey, setPublicKey] = useState()
const [channelUuid, setChannelUuid] = useState()
- const [info, setInfo] = useState()
+ const [data, setData] = useState()
const [error, setError] = useState()
const compressPublicKey = type !== 'profile'
@@ -46,9 +45,10 @@ export const useURLData = (
// return
// }
- if (!unverifiedDecodedData || !unverifiedEncodedData) {
- const hash = window.location.hash.replace('#', '')
+ const hash = window.location.hash.replace('#', '')
+ // use provided public key
+ if (!decodedData || !encodedData) {
if (!hash) {
setError('NOT_FOUND')
@@ -61,37 +61,39 @@ export const useURLData = (
})
setPublicKey(publicKey)
+
+ return
} catch (error) {
console.error(error)
setError('INVALID_PUBLIC_KEY')
+
+ return
}
+ }
+
+ // recover public key
+ let deserializedPublicKey
+ try {
+ const recoveredPublicKey = recoverPublicKeyFromEncodedURLData(
+ encodedData,
+ hash
+ )
+ deserializedPublicKey = deserializePublicKey(recoveredPublicKey, {
+ compress: compressPublicKey,
+ })
+
+ setPublicKey(deserializedPublicKey)
+ } catch (error) {
+ console.error(error)
+ setError('INVALID_PUBLIC_KEY')
return
}
- const hash = window.location.hash.replace('#', '')
- const { signature, publicKey } = decodeVerificationURLHash(hash)
-
- if (!signature || !publicKey) {
- setError('UNVERIFIED_CONTENT')
-
- return
- }
-
- if (!verifyEncodedURLData(unverifiedEncodedData, hash)) {
- setError('UNVERIFIED_CONTENT')
-
- return
- }
-
- const deserializedPublicKey = deserializePublicKey(publicKey, {
- compress: compressPublicKey,
- })
-
- const verifiedDecodedData = unverifiedDecodedData
+ // map data
switch (type) {
case 'community': {
- const data = verifiedDecodedData as Required<
+ const data = decodedData as Required<
ReturnType
>
const info: CommunityInfo = {
@@ -102,12 +104,12 @@ export const useURLData = (
tags: indicesToTags(data.tagIndices),
}
- setInfo({ type: 'community', info })
+ setData({ type: 'community', info })
- break
+ return
}
case 'channel': {
- const data = verifiedDecodedData as Required<
+ const data = decodedData as Required<
ReturnType
>
const info: Omit & {
@@ -120,13 +122,13 @@ export const useURLData = (
community: { displayName: data.community.displayName },
}
- setInfo({ type: 'channel', info })
+ setData({ type: 'channel', info })
setChannelUuid(data.uuid)
- break
+ return
}
case 'profile': {
- const data = verifiedDecodedData as Required<
+ const data = decodedData as Required<
ReturnType
>
const info: UserInfo = {
@@ -136,13 +138,11 @@ export const useURLData = (
emojiHash: publicKeyToEmojiHash(deserializedPublicKey),
}
- setInfo({ type: 'profile', info })
+ setData({ type: 'profile', info })
- break
+ return
}
}
-
- setPublicKey(deserializedPublicKey)
} catch (error) {
console.error(error)
setError('INTERNAL_SERVER_ERROR')
@@ -152,7 +152,7 @@ export const useURLData = (
return {
publicKey,
channelUuid,
- verifiedURLData: info,
+ data,
errorCode: error ? ERROR_CODES[error] : undefined,
}
}
diff --git a/apps/website/src/pages/c/[slug].tsx b/apps/website/src/pages/c/[slug].tsx
index 4ff14bab..e077bb4d 100644
--- a/apps/website/src/pages/c/[slug].tsx
+++ b/apps/website/src/pages/c/[slug].tsx
@@ -15,8 +15,8 @@ export default function CommunityPreviewPage(
return (
)
}
diff --git a/apps/website/src/pages/cc/[slug].tsx b/apps/website/src/pages/cc/[slug].tsx
index f6c816b8..b2c57b2a 100644
--- a/apps/website/src/pages/cc/[slug].tsx
+++ b/apps/website/src/pages/cc/[slug].tsx
@@ -13,8 +13,8 @@ export default function ChannelPreviewPage(
return (
)
diff --git a/apps/website/src/pages/u/[slug].tsx b/apps/website/src/pages/u/[slug].tsx
index 00c96bd3..91865de3 100644
--- a/apps/website/src/pages/u/[slug].tsx
+++ b/apps/website/src/pages/u/[slug].tsx
@@ -13,8 +13,8 @@ export default function UserPreviewPage(
return (
)
}
diff --git a/apps/website/src/server/ssr.ts b/apps/website/src/server/ssr.ts
index df8ed22e..d9e1defd 100644
--- a/apps/website/src/server/ssr.ts
+++ b/apps/website/src/server/ssr.ts
@@ -13,17 +13,13 @@ type DecodeType =
export type ServerSideProps> = {
/**
- * For verifying on client without decoding or re-encoding.
- *
- * Verification in general is done on encoded data, so it is not
- * decoded, decompressed and deserialized unnecessarily if not to be
- * displayed or othwerwise needed.
+ * For verifying on client without re-encoding.
*/
- uverifiedEncodedData: string | null
+ encodedData: string | null
/**
- * For instaneous preview even if the data is not verified yet.
+ * For instaneous preview of the content.
*/
- unverifiedDecodedData: T | null
+ decodedData: T | null
channelUuid?: string
}
@@ -46,8 +42,8 @@ export function createGetServerSideProps(decodeURLData: DecodeType) {
if (channelUuid) {
const props: ServerSideProps = {
channelUuid: channelUuid[0],
- uverifiedEncodedData: null,
- unverifiedDecodedData: null,
+ encodedData: null,
+ decodedData: null,
}
return { props }
@@ -57,8 +53,8 @@ export function createGetServerSideProps(decodeURLData: DecodeType) {
if (!encodedData) {
const props: ServerSideProps = {
- uverifiedEncodedData: null,
- unverifiedDecodedData: null,
+ encodedData: null,
+ decodedData: null,
}
return { props }
@@ -66,8 +62,8 @@ export function createGetServerSideProps(decodeURLData: DecodeType) {
const decodedData = decodeURLData(encodedData)
const props: ServerSideProps = {
- uverifiedEncodedData: encodedData,
- unverifiedDecodedData: decodedData || null,
+ encodedData,
+ decodedData: decodedData || null,
}
// fixme: set Cache-Control
diff --git a/packages/status-js/src/index.ts b/packages/status-js/src/index.ts
index 5d07bcf6..c8679441 100644
--- a/packages/status-js/src/index.ts
+++ b/packages/status-js/src/index.ts
@@ -22,4 +22,4 @@ export { createRequestClient } from './request-client/request-client'
export { deserializePublicKey } from './utils/deserialize-public-key'
export { publicKeyToColorHash } from './utils/public-key-to-color-hash'
export { publicKeyToEmojiHash } from './utils/public-key-to-emoji-hash'
-export { verifyEncodedURLData } from './utils/sign-url-data'
+export { recoverPublicKeyFromEncodedURLData } from './utils/sign-url-data'
diff --git a/packages/status-js/src/protos/url.proto b/packages/status-js/src/protos/url.proto
index b7028e3e..a8a1c697 100644
--- a/packages/status-js/src/protos/url.proto
+++ b/packages/status-js/src/protos/url.proto
@@ -23,21 +23,11 @@ message User {
string color = 3;
}
-message Verification {
- string signature = 1;
- string public_key = 2;
-}
-
message URLData {
// Community, Channel, or User
bytes content = 1;
}
-message URLHash {
- // Verification
- bytes content = 1;
-}
-
message URLParams {
string encoded_url_data = 1;
// Signature of encoded URL data
diff --git a/packages/status-js/src/protos/url_pb.ts b/packages/status-js/src/protos/url_pb.ts
index 9af218f1..b582b83a 100644
--- a/packages/status-js/src/protos/url_pb.ts
+++ b/packages/status-js/src/protos/url_pb.ts
@@ -267,61 +267,6 @@ export class User extends Message {
}
}
-/**
- * @generated from message Verification
- */
-export class Verification extends Message {
- /**
- * @generated from field: string signature = 1;
- */
- signature = ''
-
- /**
- * @generated from field: string public_key = 2;
- */
- publicKey = ''
-
- constructor(data?: PartialMessage) {
- super()
- proto3.util.initPartial(data, this)
- }
-
- static readonly runtime = proto3
- static readonly typeName = 'Verification'
- static readonly fields: FieldList = proto3.util.newFieldList(() => [
- { no: 1, name: 'signature', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
- { no: 2, name: 'public_key', kind: 'scalar', T: 9 /* ScalarType.STRING */ },
- ])
-
- static fromBinary(
- bytes: Uint8Array,
- options?: Partial
- ): Verification {
- return new Verification().fromBinary(bytes, options)
- }
-
- static fromJson(
- jsonValue: JsonValue,
- options?: Partial
- ): Verification {
- return new Verification().fromJson(jsonValue, options)
- }
-
- static fromJsonString(
- jsonString: string,
- options?: Partial
- ): Verification {
- return new Verification().fromJsonString(jsonString, options)
- }
-
- static equals(
- a: Verification | PlainMessage | undefined,
- b: Verification | PlainMessage | undefined
- ): boolean {
- return proto3.util.equals(Verification, a, b)
- }
-}
-
/**
* @generated from message URLData
*/
@@ -373,57 +318,6 @@ export class URLData extends Message {
}
}
-/**
- * @generated from message URLHash
- */
-export class URLHash extends Message {
- /**
- * Verification
- *
- * @generated from field: bytes content = 1;
- */
- content = new Uint8Array(0)
-
- constructor(data?: PartialMessage) {
- super()
- proto3.util.initPartial(data, this)
- }
-
- static readonly runtime = proto3
- static readonly typeName = 'URLHash'
- static readonly fields: FieldList = proto3.util.newFieldList(() => [
- { no: 1, name: 'content', kind: 'scalar', T: 12 /* ScalarType.BYTES */ },
- ])
-
- static fromBinary(
- bytes: Uint8Array,
- options?: Partial
- ): URLHash {
- return new URLHash().fromBinary(bytes, options)
- }
-
- static fromJson(
- jsonValue: JsonValue,
- options?: Partial
- ): URLHash {
- return new URLHash().fromJson(jsonValue, options)
- }
-
- static fromJsonString(
- jsonString: string,
- options?: Partial
- ): URLHash {
- return new URLHash().fromJsonString(jsonString, options)
- }
-
- static equals(
- a: URLHash | PlainMessage | undefined,
- b: URLHash | PlainMessage | undefined
- ): boolean {
- return proto3.util.equals(URLHash, a, b)
- }
-}
-
/**
* @generated from message URLParams
*/
diff --git a/packages/status-js/src/utils/create-url.test.ts b/packages/status-js/src/utils/create-url.test.ts
index 5aa3e8c3..b35d8555 100644
--- a/packages/status-js/src/utils/create-url.test.ts
+++ b/packages/status-js/src/utils/create-url.test.ts
@@ -66,7 +66,7 @@ describe('Create URLs', () => {
)
).toString()
).toBe(
- 'https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#Co0BClhRbk8yaHc1dFZBRS1NRDVpOE1xNHNfb0dXZDByUkZtbE9iZ1JVTlFYdFVOd1AxaXhGdzkxNFk0LUJRcEYwOEtPcXBhVUxDaDdVQ3RsV1ItTzBZUDhNd0E9EjF6UTNzaFlTSHA3R29pWGFhdUpNbkRjandVMnlOamR6cFhMb3NBV2FwUFM0Q0Z4YzEx'
+ 'https://status.app/c/iyKACkQKB0Rvb2RsZXMSJ0NvbG9yaW5nIHRoZSB3b3JsZCB3aXRoIGpveSDigKIg4bSXIOKAohiYohsiByMxMzFEMkYqAwEhMwM=#QnO2hw5tVAE-MD5i8Mq4s_oGWd0rRFmlObgRUNQXtUNwP1ixFw914Y4-BQpF08KOqpaULCh7UCtlWR-O0YP8MwA='
)
})
@@ -122,7 +122,7 @@ describe('Create URLs', () => {
)
).toString()
).toBe(
- 'https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#Co0BClg3YWVCLU02cElidnBTVkdNNFRlSmtLV1B5YTRZUkFIYnE0YW1MMGNIbFNCcFJLbjdfbHlSNGt4RURvMmhDNGtvcVBXWWVfYWsyUjljU1ZLU2lWX25OQUE9EjF6UTNzaFlTSHA3R29pWGFhdUpNbkRjandVMnlOamR6cFhMb3NBV2FwUFM0Q0Z4YzEx'
+ 'https://status.app/cc/G54AAKwObLdpiGjXnckYzRcOSq0QQAS_CURGfqVU42ceGHCObstUIknTTZDOKF3E8y2MSicncpO7fTskXnoACiPKeejvjtLTGWNxUhlT7fyQS7Jrr33UVHluxv_PLjV2ePGw5GQ33innzeK34pInIgUGs5RjdQifMVmURalxxQKwiuoY5zwIjixWWRHqjHM=#7aeB-M6pIbvpSVGM4TeJkKWPya4YRAHbq4amL0cHlSBpRKn7_lyR4kxEDo2hC4koqPWYe_ak2R9cSVKSiV_nNAA='
)
})
@@ -159,7 +159,7 @@ describe('Create URLs', () => {
)
).toString()
).toBe(
- 'https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#Co0BClhMYlFVZEpESENLb2k4RHpvWXlYODlicEtyVGpWVjNTaHFIM0U2NGJEaWZKQjJHa2VkdExCZlZLQTAyUmJVZlgwNzRwYjlpM293R3dSZFM2eF9udHhyUUE9EjF6UTNzaHdRUGhSdURKU2pWR1ZCblRqQ2RnWHk1aTlXUWFlVlBkR0pENnlUYXJKUVNq'
+ 'https://status.app/u/G10A4B0JdgwyRww90WXtnP1oNH1ZLQNM0yX0Ja9YyAMjrqSZIYINOHCbFhrnKRAcPGStPxCMJDSZlGCKzmZrJcimHY8BbcXlORrElv_BbQEegnMDPx1g9C5VVNl0fE4y#LbQUdJDHCKoi8DzoYyX89bpKrTjVV3ShqH3E64bDifJB2GkedtLBfVKA02RbUfX074pb9i3owGwRdS6x_ntxrQA='
)
})
})
diff --git a/packages/status-js/src/utils/create-url.ts b/packages/status-js/src/utils/create-url.ts
index 9dfa6412..024191f0 100644
--- a/packages/status-js/src/utils/create-url.ts
+++ b/packages/status-js/src/utils/create-url.ts
@@ -19,14 +19,12 @@ export async function createCommunityURLWithData(
communityPrivateKey: Uint8Array | string
): Promise {
const encodedURLData = encodeCommunityURLData(communityData)
- const encodedVerificationURLHash = await signEncodedURLData(
+ const encodedSignature = await signEncodedURLData(
encodedURLData,
communityPrivateKey
)
- return new URL(
- `${BASE_URL}/c/${encodedURLData}#${encodedVerificationURLHash}`
- )
+ return new URL(`${BASE_URL}/c/${encodedURLData}#${encodedSignature}`)
}
export function createChannelURLWithChatKey(
@@ -41,14 +39,12 @@ export async function createChannelURLWithData(
communityPrivateKey: Uint8Array | string
): Promise {
const encodedURLData = encodeChannelURLData(channelData)
- const encodedVerificationURLHash = await signEncodedURLData(
+ const encodedSignature = await signEncodedURLData(
encodedURLData,
communityPrivateKey
)
- return new URL(
- `${BASE_URL}/cc/${encodedURLData}#${encodedVerificationURLHash}`
- )
+ return new URL(`${BASE_URL}/cc/${encodedURLData}#${encodedSignature}`)
}
export function createUserURLWithENS(ensName: string): URL {
@@ -64,12 +60,10 @@ export async function createUserURLWithData(
userPrivateKey: Uint8Array | string
): Promise {
const encodedURLData = encodeUserURLData(userData)
- const encodedVerificationURLHash = await signEncodedURLData(
+ const encodedSignature = await signEncodedURLData(
encodedURLData,
userPrivateKey
)
- return new URL(
- `${BASE_URL}/u/${encodedURLData}#${encodedVerificationURLHash}`
- )
+ return new URL(`${BASE_URL}/u/${encodedURLData}#${encodedSignature}`)
}
diff --git a/packages/status-js/src/utils/encode-url-hash.test.ts b/packages/status-js/src/utils/encode-url-hash.test.ts
deleted file mode 100644
index 8f32538d..00000000
--- a/packages/status-js/src/utils/encode-url-hash.test.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { describe, expect, test } from 'vitest'
-
-import {
- decodeVerificationURLHash,
- encodeVerificationURLHash,
-} from './encode-url-hash'
-
-describe('Encode URL hash', () => {
- test('should encode and decode verification hash', () => {
- const data = {
- signature:
- 'k-n7d-9Pcx6ht87F4riP5xAw1v7S-e1HGMRaeaO068Q3IF1Jo8xOyeMT9Yr3Wv349Z2CdBzylw8M83CgQhcMogA=', // not generated by the pk
- publicKey: 'zQ3shUHp2rAM1yqBYeo6LhFbtrozG5mZeA6cRoGohsudtsieT',
- }
-
- const encodedHash = encodeVerificationURLHash(data)
- const decodedHash = decodeVerificationURLHash(encodedHash)
-
- expect(encodedHash).toBe(
- 'Co0BClhrLW43ZC05UGN4Nmh0ODdGNHJpUDV4QXcxdjdTLWUxSEdNUmFlYU8wNjhRM0lGMUpvOHhPeWVNVDlZcjNXdjM0OVoyQ2RCenlsdzhNODNDZ1FoY01vZ0E9EjF6UTNzaFVIcDJyQU0xeXFCWWVvNkxoRmJ0cm96RzVtWmVBNmNSb0dvaHN1ZHRzaWVU'
- )
- expect(decodedHash).toEqual(data)
- })
-})
diff --git a/packages/status-js/src/utils/encode-url-hash.ts b/packages/status-js/src/utils/encode-url-hash.ts
deleted file mode 100644
index 99d3468d..00000000
--- a/packages/status-js/src/utils/encode-url-hash.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { base64url } from '@scure/base'
-
-import { URLHash, Verification } from '../protos/url_pb'
-
-import type { PlainMessage } from '@bufbuild/protobuf'
-
-export type EncodedVerificationURLHash = string & {
- _: 'EncodedVerificationURLHash'
-}
-
-export function encodeVerificationURLHash(
- data: PlainMessage
-): EncodedVerificationURLHash {
- return encodeURLHash(
- new Verification(data).toBinary()
- ) as EncodedVerificationURLHash
-}
-
-export function decodeVerificationURLHash(
- data: string
-): PlainMessage {
- const deserialized = decodeURLHash(data)
-
- return Verification.fromBinary(
- deserialized.content
- ).toJson() as PlainMessage
-}
-
-function encodeURLHash(data: Uint8Array): string {
- const serialized = new URLHash({ content: data }).toBinary()
- const encoded = base64url.encode(serialized)
-
- return encoded
-}
-
-function decodeURLHash(data: string): URLHash {
- const decoded = base64url.decode(data)
- const deserialized = URLHash.fromBinary(decoded)
-
- return deserialized
-}
diff --git a/packages/status-js/src/utils/sign-url-data.test.ts b/packages/status-js/src/utils/sign-url-data.test.ts
index 5292b95c..c6c15585 100644
--- a/packages/status-js/src/utils/sign-url-data.test.ts
+++ b/packages/status-js/src/utils/sign-url-data.test.ts
@@ -1,7 +1,9 @@
import { expect, test } from 'vitest'
-import { encodeVerificationURLHash } from './encode-url-hash'
-import { signEncodedURLData, verifyEncodedURLData } from './sign-url-data'
+import {
+ recoverPublicKeyFromEncodedURLData,
+ signEncodedURLData,
+} from './sign-url-data'
import type { EncodedURLData } from './encode-url-data'
@@ -13,50 +15,41 @@ const publicKey =
'0x04f9134866f2bd8f45f2bc7893c95a6b989378c370088c9a1a5a53eda2ebb8a1e8386921592b6bd56fc3573f03c46df3396cc42e2993cdc001855c858865d768a7'
const encodedURLData =
'G74AgK0ObFNmYT-WC_Jcc9KfSjHXAQo9THKEEbgPaJoItceMES-bUxr2Tj9efv447rRefBIUg9CEsSFyjBOFTRdZ9PH2wUOW8hVNYqIje3BC96mZ8uFogqM6k7gCCJnMHy4ulsmsgHTdeh5dAzTNNuG8m9XB8oVeildTCKlRhINnTZh4kAl5sP8SzBB4V2_I41a8PKl3mcS0z_eF5gA=' as EncodedURLData
+const encodedSignature =
+ 'k-n7d-9Pcx6ht87F4riP5xAw1v7S-e1HGMRaeaO068Q3IF1Jo8xOyeMT9Yr3Wv349Z2CdBzylw8M83CgQhcMogA='
-test('should verify URL data and correspoinding signature', async () => {
- const encodedVerificationURLHash = await signEncodedURLData(
- encodedURLData,
- privateKey
- )
-
- expect(verifyEncodedURLData(encodedURLData, encodedVerificationURLHash)).toBe(
- true
+test('should sign URL data', async () => {
+ expect(await signEncodedURLData(encodedURLData, privateKey)).toBe(
+ encodedSignature
)
})
-test('should not verify URL data and random signature', async () => {
- const randomSignature =
+test('should recover original public key from URL data', async () => {
+ expect(
+ await recoverPublicKeyFromEncodedURLData(encodedURLData, encodedSignature)
+ ).toBe(publicKey)
+})
+
+test('should not recover original public key from same URL data but changed signature', async () => {
+ const changedEncodedSignature =
'OyOgY6Zta8S7U4l5Bv_9E_7snALhixwvjxORVAVJ-YJk-tMSGgstOy5XEEQx25TQJIAtpWf8eHnEmV8V-GmouQA='
- const encodedVerificationURLHash = encodeVerificationURLHash({
- signature: randomSignature,
- publicKey,
- })
-
- expect(verifyEncodedURLData(encodedURLData, encodedVerificationURLHash)).toBe(
- false
- )
- // see https://github.com/paulmillr/noble-secp256k1/issues/43#issuecomment-1020214968
- // expect(verifyEncodedURLData(randomSignature, encodedURLData)).toBe(false)
+ expect(
+ await recoverPublicKeyFromEncodedURLData(
+ encodedURLData,
+ changedEncodedSignature
+ )
+ ).not.toBe(publicKey)
})
-test('should not verify random URL data and random signature', async () => {
- const randomEncodedURLData =
+test('should not recover original public key from same signature but changed URL data', async () => {
+ const changedEncodedURLData =
'CyeACk0KHkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBlZ2VzdGFzLhIYV2UgZG8gbm90IHN1cHBvcnQgQWxpY2UuGMCEPSIHIzQzNjBERioEAQIDBAM=' as EncodedURLData
- const randomSignature =
- 'k-n7d-9Pcx6ht87F4riP5xAw1v7S-e1HGMRaeaO068Q3IF1Jo8xOyeMT9Yr3Wv349Z2CdBzylw8M83CgQhcMogA='
-
- const encodedVerificationURLHash = encodeVerificationURLHash({
- signature: randomSignature,
- publicKey,
- })
expect(
- verifyEncodedURLData(randomEncodedURLData, encodedVerificationURLHash)
- ).toBe(false)
- // see https://github.com/paulmillr/noble-secp256k1/issues/43#issuecomment-1020214968
- // expect(verifyEncodedURLData(randomSignature, randomEncodedURLData)).toBe(
- // false
- // )
+ await recoverPublicKeyFromEncodedURLData(
+ changedEncodedURLData,
+ encodedSignature
+ )
+ ).not.toBe(publicKey)
})
diff --git a/packages/status-js/src/utils/sign-url-data.ts b/packages/status-js/src/utils/sign-url-data.ts
index 4d92abfc..7b06dfdd 100644
--- a/packages/status-js/src/utils/sign-url-data.ts
+++ b/packages/status-js/src/utils/sign-url-data.ts
@@ -1,51 +1,30 @@
import { base64url } from '@scure/base'
-import { getPublicKey } from 'ethereum-cryptography/secp256k1'
-import { bytesToHex } from 'ethereum-cryptography/utils'
+import { toHex, utf8ToBytes as toBytes } from 'ethereum-cryptography/utils'
-import { deserializePublicKey } from './deserialize-public-key'
-import {
- decodeVerificationURLHash,
- encodeVerificationURLHash,
-} from './encode-url-hash'
-import { serializePublicKey } from './serialize-public-key'
-import { signData, verifySignedData } from './sign-data'
+import { recoverPublicKey } from './recover-public-key'
+import { signData } from './sign-data'
import type { EncodedURLData } from './encode-url-data'
-import type { EncodedVerificationURLHash } from './encode-url-hash'
export async function signEncodedURLData(
encodedURLData: EncodedURLData,
privateKey: Uint8Array | string
-): Promise {
+): Promise {
const signature = await signData(encodedURLData, privateKey)
-
const encodedSignature = base64url.encode(signature)
- const serializedPublicKey = serializePublicKey(
- `0x${bytesToHex(getPublicKey(privateKey))}`
- )
- return encodeVerificationURLHash({
- signature: encodedSignature,
- publicKey: serializedPublicKey,
- })
+ return encodedSignature
}
-export function verifyEncodedURLData(
+export function recoverPublicKeyFromEncodedURLData(
encodedURLData: string,
- encodedVerificationURLHash: string
-): boolean {
- const { signature, publicKey } = decodeVerificationURLHash(
- encodedVerificationURLHash
- )
-
- const decodedSignature = base64url.decode(signature)
- const deserializedPublicKey = deserializePublicKey(publicKey, {
- compress: false,
- })
-
- return verifySignedData(
+ encodedSignature: string
+): string {
+ const decodedSignature = base64url.decode(encodedSignature)
+ const recoveredPublicKey = recoverPublicKey(
decodedSignature,
- encodedURLData,
- deserializedPublicKey
+ toBytes(encodedURLData)
)
+
+ return `0x${toHex(recoveredPublicKey)}`
}
diff --git a/packages/status-js/vite.config.ts b/packages/status-js/vite.config.ts
index ca0b8d09..cf703902 100644
--- a/packages/status-js/vite.config.ts
+++ b/packages/status-js/vite.config.ts
@@ -26,11 +26,7 @@ export default defineConfig(({ mode }) => {
build: {
target: 'es2020',
lib: {
- entry: [
- './src/index.ts',
- './src/utils/encode-url-data.ts',
- './src/utils/encode-url-hash.ts',
- ],
+ entry: ['./src/index.ts', './src/utils/encode-url-data.ts'],
fileName: (format, entryName) => {
if (!['es'].includes(format)) {
throw new Error(`Unexpected format: ${format}`)