new release #190
@ -18,3 +18,4 @@ export const SET_RELAY_MAP_UPDATED = 'SET_RELAY_MAP_UPDATED'
|
|||||||
|
|
||||||
export const UPDATE_USER_APP_DATA = 'UPDATE_USER_APP_DATA'
|
export const UPDATE_USER_APP_DATA = 'UPDATE_USER_APP_DATA'
|
||||||
export const UPDATE_PROCESSED_GIFT_WRAPS = 'UPDATE_PROCESSED_GIFT_WRAPS'
|
export const UPDATE_PROCESSED_GIFT_WRAPS = 'UPDATE_PROCESSED_GIFT_WRAPS'
|
||||||
|
export const SET_D_TAG_FOR_APP_DATA = 'SET_D_TAG_FOR_APP_DATA'
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
import { UserAppData } from '../../types'
|
import { UserAppData } from '../../types'
|
||||||
import * as ActionTypes from '../actionTypes'
|
import * as ActionTypes from '../actionTypes'
|
||||||
import { UpdateProcessedGiftWraps, UpdateUserAppData } from './types'
|
import {
|
||||||
|
SetDTagForAppData,
|
||||||
|
UpdateProcessedGiftWraps,
|
||||||
|
UpdateUserAppData
|
||||||
|
} from './types'
|
||||||
|
|
||||||
export const updateUserAppData = (payload: UserAppData): UpdateUserAppData => ({
|
export const updateUserAppData = (payload: UserAppData): UpdateUserAppData => ({
|
||||||
type: ActionTypes.UPDATE_USER_APP_DATA,
|
type: ActionTypes.UPDATE_USER_APP_DATA,
|
||||||
@ -13,3 +17,8 @@ export const updateProcessedGiftWraps = (
|
|||||||
type: ActionTypes.UPDATE_PROCESSED_GIFT_WRAPS,
|
type: ActionTypes.UPDATE_PROCESSED_GIFT_WRAPS,
|
||||||
payload
|
payload
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const setDTagForAppData = (payload: string): SetDTagForAppData => ({
|
||||||
|
type: ActionTypes.SET_D_TAG_FOR_APP_DATA,
|
||||||
|
payload
|
||||||
|
})
|
||||||
|
@ -24,6 +24,12 @@ const reducer = (
|
|||||||
processedGiftWraps: action.payload
|
processedGiftWraps: action.payload
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ActionTypes.SET_D_TAG_FOR_APP_DATA:
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
dTag: action.payload
|
||||||
|
}
|
||||||
|
|
||||||
case ActionTypes.RESTORE_STATE:
|
case ActionTypes.RESTORE_STATE:
|
||||||
return action.payload.userAppData || null
|
return action.payload.userAppData || null
|
||||||
|
|
||||||
|
@ -12,7 +12,13 @@ export interface UpdateProcessedGiftWraps {
|
|||||||
payload: string[]
|
payload: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetDTagForAppData {
|
||||||
|
type: typeof ActionTypes.SET_D_TAG_FOR_APP_DATA
|
||||||
|
payload: string
|
||||||
|
}
|
||||||
|
|
||||||
export type UserAppDataDispatchTypes =
|
export type UserAppDataDispatchTypes =
|
||||||
| UpdateUserAppData
|
| UpdateUserAppData
|
||||||
| UpdateProcessedGiftWraps
|
| UpdateProcessedGiftWraps
|
||||||
|
| SetDTagForAppData
|
||||||
| RestoreState
|
| RestoreState
|
||||||
|
@ -43,6 +43,7 @@ export interface UserAppData {
|
|||||||
sigits: { [key: string]: Meta } // key will be id of create signature
|
sigits: { [key: string]: Meta } // key will be id of create signature
|
||||||
processedGiftWraps: string[] // an array of ids of processed gift wrapped events
|
processedGiftWraps: string[] // an array of ids of processed gift wrapped events
|
||||||
keyPair?: Keys // this key pair is used for blossom requests authentication
|
keyPair?: Keys // this key pair is used for blossom requests authentication
|
||||||
|
dTag?: string // this will be used for d tag in 30078 kind of events
|
||||||
blossomUrls: string[] // array for storing Urls for the files that stores all the sigits and processedGiftWraps on blossom
|
blossomUrls: string[] // array for storing Urls for the files that stores all the sigits and processedGiftWraps on blossom
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ import {
|
|||||||
getEventHash,
|
getEventHash,
|
||||||
getPublicKey,
|
getPublicKey,
|
||||||
kinds,
|
kinds,
|
||||||
|
nip04,
|
||||||
nip19,
|
nip19,
|
||||||
nip44,
|
nip44,
|
||||||
verifyEvent
|
verifyEvent
|
||||||
@ -23,6 +24,7 @@ import {
|
|||||||
relayController
|
relayController
|
||||||
} from '../controllers'
|
} from '../controllers'
|
||||||
import {
|
import {
|
||||||
|
setDTagForAppData,
|
||||||
updateProcessedGiftWraps,
|
updateProcessedGiftWraps,
|
||||||
updateUserAppData as updateUserAppDataAction
|
updateUserAppData as updateUserAppDataAction
|
||||||
} from '../store/actions'
|
} from '../store/actions'
|
||||||
@ -30,10 +32,54 @@ import { AuthState, Keys } from '../store/auth/types'
|
|||||||
import { RelaysState } from '../store/relays/types'
|
import { RelaysState } from '../store/relays/types'
|
||||||
import store from '../store/store'
|
import store from '../store/store'
|
||||||
import { Meta, SignedEvent, UserAppData } from '../types'
|
import { Meta, SignedEvent, UserAppData } from '../types'
|
||||||
import { getHash } from './hash'
|
import { getDefaultRelayMap } from './relays'
|
||||||
import { parseJson, removeLeadingSlash } from './string'
|
import { parseJson, removeLeadingSlash } from './string'
|
||||||
import { timeout } from './utils'
|
import { timeout } from './utils'
|
||||||
import { getDefaultRelayMap } from './relays'
|
|
||||||
|
/**
|
||||||
|
* Generates a `d` tag for userAppData
|
||||||
|
*/
|
||||||
|
const getDTagForUserAppData = async (): Promise<string | null> => {
|
||||||
|
const isLoggedIn = store.getState().auth?.loggedIn
|
||||||
|
const pubkey = store.getState().auth?.usersPubkey
|
||||||
|
|
||||||
|
if (!isLoggedIn || !pubkey) {
|
||||||
|
throw new Error(
|
||||||
|
'For generating d tag user must be logged in and a valid pubkey should exists in app Store'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let dTag = store.getState().userAppData?.dTag
|
||||||
|
|
||||||
|
// if dTag is found in redux store then just return that
|
||||||
|
if (dTag) return dTag
|
||||||
|
|
||||||
|
// dTag not found is redux store. Generate it.
|
||||||
|
const unsignedEvent: UnsignedEvent = {
|
||||||
|
kind: kinds.ShortTextNote,
|
||||||
|
pubkey: pubkey,
|
||||||
|
created_at: 0,
|
||||||
|
tags: [],
|
||||||
|
content: `938_${pubkey}`
|
||||||
|
}
|
||||||
|
|
||||||
|
const nostrController = NostrController.getInstance()
|
||||||
|
const signedEvent = await nostrController
|
||||||
|
.signEvent(unsignedEvent)
|
||||||
|
.catch((err) => {
|
||||||
|
console.error('Failed to sign event for dTag', err)
|
||||||
|
toast.error(err.message || err)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
if (!signedEvent) return null
|
||||||
|
|
||||||
|
dTag = signedEvent.sig
|
||||||
|
|
||||||
|
// save dTag in redux store
|
||||||
|
store.dispatch(setDTagForAppData(dTag))
|
||||||
|
|
||||||
|
return dTag
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param hexKey hex private or public key
|
* @param hexKey hex private or public key
|
||||||
@ -377,13 +423,13 @@ export const getUsersAppData = async (): Promise<UserAppData | null> => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate an identifier for the user's nip78
|
// Generate an identifier for the user's nip78
|
||||||
const hash = await getHash('938' + usersPubkey)
|
const dTag = await getDTagForUserAppData()
|
||||||
if (!hash) return null
|
if (!dTag) return null
|
||||||
|
|
||||||
// Define a filter for fetching events
|
// Define a filter for fetching events
|
||||||
const filter: Filter = {
|
const filter: Filter = {
|
||||||
kinds: [kinds.Application],
|
kinds: [kinds.Application],
|
||||||
'#d': [hash]
|
'#d': [dTag]
|
||||||
}
|
}
|
||||||
|
|
||||||
const encryptedContent = await relayController
|
const encryptedContent = await relayController
|
||||||
@ -578,14 +624,14 @@ export const updateUsersAppData = async (meta: Meta) => {
|
|||||||
if (!encryptedContent) return null
|
if (!encryptedContent) return null
|
||||||
|
|
||||||
// generate the identifier for user's appData event
|
// generate the identifier for user's appData event
|
||||||
const hash = await getHash('938' + usersPubkey)
|
const dTag = await getDTagForUserAppData()
|
||||||
if (!hash) return null
|
if (!dTag) return null
|
||||||
|
|
||||||
const updatedEvent: UnsignedEvent = {
|
const updatedEvent: UnsignedEvent = {
|
||||||
kind: kinds.Application,
|
kind: kinds.Application,
|
||||||
pubkey: usersPubkey!,
|
pubkey: usersPubkey!,
|
||||||
created_at: unixNow(),
|
created_at: unixNow(),
|
||||||
tags: [['d', hash]],
|
tags: [['d', dTag]],
|
||||||
content: encryptedContent
|
content: encryptedContent
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,9 +739,10 @@ const uploadUserAppDataToBlossom = async (
|
|||||||
// Convert the private key from hex to bytes
|
// Convert the private key from hex to bytes
|
||||||
const secretKey = hexToBytes(privateKey)
|
const secretKey = hexToBytes(privateKey)
|
||||||
// Encrypt the JSON string using the secret key
|
// Encrypt the JSON string using the secret key
|
||||||
const encrypted = nip44.v2.encrypt(
|
const encrypted = await nip04.encrypt(
|
||||||
stringified,
|
secretKey,
|
||||||
nip44ConversationKey(secretKey, getPublicKey(secretKey))
|
getPublicKey(secretKey),
|
||||||
|
stringified
|
||||||
)
|
)
|
||||||
|
|
||||||
// Create a blob from the encrypted data
|
// Create a blob from the encrypted data
|
||||||
@ -788,10 +835,7 @@ const getUserAppDataFromBlossom = async (url: string, privateKey: string) => {
|
|||||||
const pubkey = getPublicKey(secret)
|
const pubkey = getPublicKey(secret)
|
||||||
|
|
||||||
// Decrypt the encrypted data using the secret and public key
|
// Decrypt the encrypted data using the secret and public key
|
||||||
const decrypted = nip44.v2.decrypt(
|
const decrypted = await nip04.decrypt(secret, pubkey, encrypted)
|
||||||
encrypted,
|
|
||||||
nip44ConversationKey(secret, pubkey)
|
|
||||||
)
|
|
||||||
|
|
||||||
// Parse the decrypted JSON content
|
// Parse the decrypted JSON content
|
||||||
const parsedContent = await parseJson<{
|
const parsedContent = await parseJson<{
|
||||||
|
Loading…
Reference in New Issue
Block a user