mirror of
https://github.com/Myzel394/kleckrelay-website.git
synced 2025-06-20 00:05:26 +02:00
added AuthContext; fixed signing up; improvements & bugfixes
This commit is contained in:
parent
ade221be7d
commit
bb4c58508d
@ -30,6 +30,7 @@
|
|||||||
"react-use": "^17.4.0",
|
"react-use": "^17.4.0",
|
||||||
"secure-random-password": "^0.2.3",
|
"secure-random-password": "^0.2.3",
|
||||||
"ua-parser-js": "^1.0.2",
|
"ua-parser-js": "^1.0.2",
|
||||||
|
"use-system-theme": "^0.1.1",
|
||||||
"yup": "^0.32.11"
|
"yup": "^0.32.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import {createContext} from "react"
|
import {createContext} from "react"
|
||||||
|
|
||||||
import {User} from "~/server-types"
|
import {ServerUser, User} from "~/server-types"
|
||||||
|
|
||||||
interface AuthContextTypeBase {
|
interface AuthContextTypeBase {
|
||||||
user: User | null
|
user: ServerUser | User | null
|
||||||
isAuthenticated: boolean
|
isAuthenticated: boolean
|
||||||
login: (user: User, callback: () => void) => Promise<void>
|
login: (user: ServerUser, callback?: () => void) => Promise<void>
|
||||||
logout: () => void
|
logout: () => void
|
||||||
_decryptContent: (content: string) => string
|
_decryptContent: (content: string) => string
|
||||||
_encryptContent: (content: string) => string
|
_encryptContent: (content: string) => string
|
||||||
_setMasterPassword: (masterPassword: string) => void
|
_setDecryptionPassword: (decryptionPassword: string) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AuthContextTypeAuthenticated {
|
interface AuthContextTypeAuthenticated {
|
||||||
user: User
|
user: ServerUser
|
||||||
isAuthenticated: true
|
isAuthenticated: true
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +41,8 @@ const AuthContext = createContext<AuthContextType>({
|
|||||||
_encryptContent: () => {
|
_encryptContent: () => {
|
||||||
throw new Error("_encryptContent() not implemented")
|
throw new Error("_encryptContent() not implemented")
|
||||||
},
|
},
|
||||||
_setMasterPassword: () => {
|
_setDecryptionPassword: () => {
|
||||||
throw new Error("_setMasterPassword() not implemented")
|
throw new Error("_setMasterDecryptionPassword() not implemented")
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -1,17 +1,10 @@
|
|||||||
import {
|
import {ReactElement, ReactNode, useCallback, useEffect, useMemo} from "react"
|
||||||
ReactElement,
|
|
||||||
ReactNode,
|
|
||||||
useCallback,
|
|
||||||
useEffect,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from "react"
|
|
||||||
import {useLocalStorage} from "react-use"
|
import {useLocalStorage} from "react-use"
|
||||||
import {AxiosError} from "axios"
|
import {AxiosError} from "axios"
|
||||||
|
|
||||||
import {useMutation} from "@tanstack/react-query"
|
import {useMutation} from "@tanstack/react-query"
|
||||||
|
|
||||||
import {User} from "~/server-types"
|
import {ServerUser, User} from "~/server-types"
|
||||||
import {
|
import {
|
||||||
REFRESH_TOKEN_URL,
|
REFRESH_TOKEN_URL,
|
||||||
RefreshTokenResult,
|
RefreshTokenResult,
|
||||||
@ -30,11 +23,20 @@ export interface AuthContextProviderProps {
|
|||||||
export default function AuthContextProvider({
|
export default function AuthContextProvider({
|
||||||
children,
|
children,
|
||||||
}: AuthContextProviderProps): ReactElement {
|
}: AuthContextProviderProps): ReactElement {
|
||||||
const [masterPassword, setMasterPassword] = useState<string | null>(null)
|
const [decryptionPassword, setDecryptionPassword] = useLocalStorage<
|
||||||
const [user, setUser] = useLocalStorage<User | null>(
|
string | null
|
||||||
|
>("_global-context-auth-decryption-password", null)
|
||||||
|
const [user, setUser] = useLocalStorage<ServerUser | User | null>(
|
||||||
"_global-context-auth-user",
|
"_global-context-auth-user",
|
||||||
null,
|
null,
|
||||||
)
|
)
|
||||||
|
const masterPassword = useMemo<string | null>(() => {
|
||||||
|
if (decryptionPassword === null || !user?.encryptedPassword) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return decryptString(user!.encryptedPassword, decryptionPassword!)
|
||||||
|
}, [user?.encryptedPassword, decryptionPassword])
|
||||||
|
|
||||||
const logout = useCallback(async (forceLogout = true) => {
|
const logout = useCallback(async (forceLogout = true) => {
|
||||||
setUser(null)
|
setUser(null)
|
||||||
@ -44,12 +46,6 @@ export default function AuthContextProvider({
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const login = useCallback(async (user: User, callback?: () => void) => {
|
|
||||||
setUser(user)
|
|
||||||
|
|
||||||
callback?.()
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const encryptContent = useCallback(
|
const encryptContent = useCallback(
|
||||||
(content: string) => {
|
(content: string) => {
|
||||||
if (!masterPassword) {
|
if (!masterPassword) {
|
||||||
@ -72,6 +68,27 @@ export default function AuthContextProvider({
|
|||||||
[masterPassword],
|
[masterPassword],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const login = useCallback(
|
||||||
|
async (user: ServerUser, callback?: () => void) => {
|
||||||
|
if (masterPassword !== null && user.encryptedNotes) {
|
||||||
|
const note = JSON.parse(decryptContent(user.encryptedNotes))
|
||||||
|
|
||||||
|
const newUser: User = {
|
||||||
|
...user,
|
||||||
|
notes: note,
|
||||||
|
isDecrypted: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
setUser(newUser)
|
||||||
|
} else {
|
||||||
|
setUser(user)
|
||||||
|
}
|
||||||
|
|
||||||
|
callback?.()
|
||||||
|
},
|
||||||
|
[masterPassword, decryptContent],
|
||||||
|
)
|
||||||
|
|
||||||
const {mutateAsync: refresh} = useMutation<
|
const {mutateAsync: refresh} = useMutation<
|
||||||
RefreshTokenResult,
|
RefreshTokenResult,
|
||||||
AxiosError,
|
AxiosError,
|
||||||
@ -86,9 +103,9 @@ export default function AuthContextProvider({
|
|||||||
login,
|
login,
|
||||||
logout,
|
logout,
|
||||||
isAuthenticated: user !== null,
|
isAuthenticated: user !== null,
|
||||||
_setMasterPassword: setMasterPassword,
|
|
||||||
_encryptContent: encryptContent,
|
_encryptContent: encryptContent,
|
||||||
_decryptContent: decryptContent,
|
_decryptContent: decryptContent,
|
||||||
|
_setDecryptionPassword: setDecryptionPassword,
|
||||||
}),
|
}),
|
||||||
[refresh, login, logout],
|
[refresh, login, logout],
|
||||||
)
|
)
|
||||||
|
@ -41,6 +41,9 @@ export default async function createAlias(
|
|||||||
const {data} = await client.post(
|
const {data} = await client.post(
|
||||||
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
|
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
|
||||||
aliasData,
|
aliasData,
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -4,6 +4,9 @@ import {client} from "~/constants/axios-client"
|
|||||||
export default async function getAliases(): Promise<Array<Alias>> {
|
export default async function getAliases(): Promise<Array<Alias>> {
|
||||||
const {data} = await client.get(
|
const {data} = await client.get(
|
||||||
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
|
`${import.meta.env.VITE_SERVER_BASE_URL}/alias`,
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return data
|
return data
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
import {User} from "~/server-types"
|
import {ServerUser} from "~/server-types"
|
||||||
|
|
||||||
export default function parseUser(user: any): User {
|
export default function parseUser(user: any): ServerUser {
|
||||||
return {
|
return {
|
||||||
...user,
|
...user,
|
||||||
|
isDecrypted: false,
|
||||||
createdAt: new Date(user.createdAt),
|
createdAt: new Date(user.createdAt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import {User} from "~/server-types"
|
import {ServerUser} from "~/server-types"
|
||||||
import {client} from "~/constants/axios-client"
|
import {client} from "~/constants/axios-client"
|
||||||
|
|
||||||
export interface RefreshTokenResult {
|
export interface RefreshTokenResult {
|
||||||
user: User
|
user: ServerUser
|
||||||
detail: string
|
detail: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {client} from "~/constants/axios-client"
|
import {client} from "~/constants/axios-client"
|
||||||
|
|
||||||
export interface SignupResult {
|
export interface SignupResult {
|
||||||
normalized_email: string
|
normalizedEmail: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function signup(email: string): Promise<SignupResult> {
|
export default async function signup(email: string): Promise<SignupResult> {
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
import {Language} from "~/server-types"
|
import {AuthenticationDetails, Language} from "~/server-types"
|
||||||
import {client} from "~/constants/axios-client"
|
import {client} from "~/constants/axios-client"
|
||||||
import parseUser from "~/apis/helpers/parse-user"
|
import parseUser from "~/apis/helpers/parse-user"
|
||||||
|
|
||||||
export interface UpdateAccountData {
|
export interface UpdateAccountData {
|
||||||
password: string
|
encryptedPassword?: string
|
||||||
publicKey: string
|
encryptedNotes?: string
|
||||||
encryptedPrivateKey: string
|
publicKey?: string
|
||||||
language: Language
|
language?: Language
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function updateAccount(
|
export default async function updateAccount(
|
||||||
updateData: Partial<UpdateAccountData>,
|
updateData: UpdateAccountData,
|
||||||
): Promise<void> {
|
): Promise<AuthenticationDetails> {
|
||||||
const {data} = await client.patch(
|
const {data} = await client.patch(
|
||||||
`${import.meta.env.VITE_SERVER_BASE_URL}/account`,
|
`${import.meta.env.VITE_SERVER_BASE_URL}/account`,
|
||||||
updateData,
|
updateData,
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -17,8 +17,10 @@ export default async function verifyEmail({
|
|||||||
email: email,
|
email: email,
|
||||||
token: token,
|
token: token,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
withCredentials: true,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
console.log(data)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...data,
|
...data,
|
||||||
|
@ -4,3 +4,5 @@ export * from "./use-query-params"
|
|||||||
export {default as useQueryParams} from "./use-query-params"
|
export {default as useQueryParams} from "./use-query-params"
|
||||||
export * from "./use-user"
|
export * from "./use-user"
|
||||||
export {default as useUser} from "./use-user"
|
export {default as useUser} from "./use-user"
|
||||||
|
export * from "./use-system-preferred-theme"
|
||||||
|
export {default as useSystemPreferredTheme} from "./use-system-preferred-theme"
|
||||||
|
9
src/hooks/use-system-preferred-theme.ts
Normal file
9
src/hooks/use-system-preferred-theme.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import {useMedia} from "react-use"
|
||||||
|
|
||||||
|
import {Theme} from "~/server-types"
|
||||||
|
|
||||||
|
export default function useSystemPreferredTheme(): Theme {
|
||||||
|
const prefersDark = useMedia("(prefers-color-scheme: dark)")
|
||||||
|
|
||||||
|
return prefersDark ? Theme.DARK : Theme.LIGHT
|
||||||
|
}
|
@ -1,20 +1,30 @@
|
|||||||
import {useNavigate} from "react-router-dom"
|
import {useLocation, useNavigate} from "react-router-dom"
|
||||||
import {useContext, useLayoutEffect} from "react"
|
import {useContext, useLayoutEffect} from "react"
|
||||||
|
|
||||||
import {User} from "~/server-types"
|
import {ServerUser} from "~/server-types"
|
||||||
import AuthContext from "~/AuthContext/AuthContext"
|
import AuthContext from "~/AuthContext/AuthContext"
|
||||||
|
|
||||||
|
const AUTHENTICATION_PATHS = [
|
||||||
|
"/auth/login",
|
||||||
|
"/auth/signup",
|
||||||
|
"/auth/complete-account",
|
||||||
|
]
|
||||||
|
|
||||||
/// Returns the currently authenticated user.
|
/// Returns the currently authenticated user.
|
||||||
// If the user is not authenticated, it will automatically redirect to the login page.
|
// If the user is not authenticated, it will automatically redirect to the login page.
|
||||||
export default function useUser(): User {
|
export default function useUser(): ServerUser {
|
||||||
|
const location = useLocation()
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
const {user, isAuthenticated} = useContext(AuthContext)
|
const {user, isAuthenticated} = useContext(AuthContext)
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!isAuthenticated) {
|
if (
|
||||||
|
!isAuthenticated &&
|
||||||
|
!AUTHENTICATION_PATHS.includes(location.pathname)
|
||||||
|
) {
|
||||||
navigate("/auth/login")
|
navigate("/auth/login")
|
||||||
}
|
}
|
||||||
}, [isAuthenticated, navigate])
|
}, [isAuthenticated, navigate])
|
||||||
|
|
||||||
return user as User
|
return user as ServerUser
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import * as yup from "yup"
|
import * as yup from "yup"
|
||||||
import {useFormik} from "formik"
|
import {useFormik} from "formik"
|
||||||
import {MdCheckCircle, MdChevronRight, MdLock} from "react-icons/md"
|
import {MdCheckCircle, MdChevronRight, MdLock} from "react-icons/md"
|
||||||
import {generateKey} from "openpgp"
|
import {generateKey, readKey} from "openpgp"
|
||||||
import React, {ReactElement, useMemo} from "react"
|
import React, {ReactElement, useContext, useMemo} from "react"
|
||||||
import passwordGenerator from "secure-random-password"
|
import passwordGenerator from "secure-random-password"
|
||||||
|
|
||||||
import {LoadingButton} from "@mui/lab"
|
import {LoadingButton} from "@mui/lab"
|
||||||
@ -12,8 +12,14 @@ import {useMutation} from "@tanstack/react-query"
|
|||||||
import {PasswordField} from "~/components"
|
import {PasswordField} from "~/components"
|
||||||
import {buildEncryptionPassword, encryptString} from "~/utils"
|
import {buildEncryptionPassword, encryptString} from "~/utils"
|
||||||
import {isDev} from "~/constants/development"
|
import {isDev} from "~/constants/development"
|
||||||
import {useUser} from "~/hooks"
|
import {useSystemPreferredTheme, useUser} from "~/hooks"
|
||||||
import {MASTER_PASSWORD_LENGTH} from "~/constants/values"
|
import {MASTER_PASSWORD_LENGTH} from "~/constants/values"
|
||||||
|
import {AuthenticationDetails, UserNote} from "~/server-types"
|
||||||
|
import {AxiosError} from "axios"
|
||||||
|
import {UpdateAccountData, updateAccount} from "~/apis"
|
||||||
|
import {encryptUserNote} from "~/utils/encrypt-user-note"
|
||||||
|
import {useNavigate} from "react-router-dom"
|
||||||
|
import AuthContext from "~/AuthContext/AuthContext"
|
||||||
|
|
||||||
interface Form {
|
interface Form {
|
||||||
password: string
|
password: string
|
||||||
@ -31,19 +37,32 @@ const schema = yup.object().shape({
|
|||||||
|
|
||||||
export default function PasswordForm(): ReactElement {
|
export default function PasswordForm(): ReactElement {
|
||||||
const user = useUser()
|
const user = useUser()
|
||||||
const {} = useMutation<>()
|
const theme = useSystemPreferredTheme()
|
||||||
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
const {_setDecryptionPassword, login} = useContext(AuthContext)
|
||||||
|
|
||||||
const awaitGenerateKey = useMemo(
|
const awaitGenerateKey = useMemo(
|
||||||
() =>
|
() =>
|
||||||
generateKey({
|
generateKey({
|
||||||
type: "rsa",
|
type: "rsa",
|
||||||
format: "armored",
|
format: "armored",
|
||||||
curve: "curve25519",
|
|
||||||
userIDs: [{name: "John Smith", email: "john@example.com"}],
|
userIDs: [{name: "John Smith", email: "john@example.com"}],
|
||||||
passphrase: "",
|
passphrase: "",
|
||||||
rsaBits: isDev ? 2048 : 4096,
|
rsaBits: isDev ? 2048 : 4096,
|
||||||
}),
|
}),
|
||||||
[],
|
[],
|
||||||
)
|
)
|
||||||
|
const {mutateAsync} = useMutation<
|
||||||
|
AuthenticationDetails,
|
||||||
|
AxiosError,
|
||||||
|
UpdateAccountData
|
||||||
|
>(updateAccount, {
|
||||||
|
onSuccess: ({user}) => {
|
||||||
|
login(user)
|
||||||
|
navigate("/")
|
||||||
|
},
|
||||||
|
})
|
||||||
const formik = useFormik<Form>({
|
const formik = useFormik<Form>({
|
||||||
validationSchema: schema,
|
validationSchema: schema,
|
||||||
initialValues: {
|
initialValues: {
|
||||||
@ -64,12 +83,27 @@ export default function PasswordForm(): ReactElement {
|
|||||||
)
|
)
|
||||||
const encryptedMasterPassword = encryptString(
|
const encryptedMasterPassword = encryptString(
|
||||||
masterPassword,
|
masterPassword,
|
||||||
`${values.password}-${user.email.address}`,
|
encryptionPassword,
|
||||||
)
|
|
||||||
const encryptedPrivateKey = encryptString(
|
|
||||||
keyPair.privateKey,
|
|
||||||
masterPassword,
|
|
||||||
)
|
)
|
||||||
|
const note: UserNote = {
|
||||||
|
theme,
|
||||||
|
privateKey: keyPair.privateKey,
|
||||||
|
}
|
||||||
|
const encryptedNotes = encryptUserNote(note, masterPassword)
|
||||||
|
|
||||||
|
_setDecryptionPassword(values.password)
|
||||||
|
|
||||||
|
await mutateAsync({
|
||||||
|
encryptedPassword: encryptedMasterPassword,
|
||||||
|
publicKey: (
|
||||||
|
await readKey({
|
||||||
|
armoredKey: keyPair.publicKey,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.toPublic()
|
||||||
|
.armor(),
|
||||||
|
encryptedNotes,
|
||||||
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setErrors({detail: "An error occurred"})
|
setErrors({detail: "An error occurred"})
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ export default function EmailForm({
|
|||||||
const {mutateAsync} = useMutation<SignupResult, AxiosError, string>(
|
const {mutateAsync} = useMutation<SignupResult, AxiosError, string>(
|
||||||
signup,
|
signup,
|
||||||
{
|
{
|
||||||
onSuccess: ({normalized_email}) => onSignUp(normalized_email),
|
onSuccess: ({normalizedEmail}) => onSignUp(normalizedEmail),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
const formik = useFormik<Form>({
|
const formik = useFormik<Form>({
|
||||||
@ -112,9 +112,9 @@ export default function EmailForm({
|
|||||||
</SimpleForm>
|
</SimpleForm>
|
||||||
</form>
|
</form>
|
||||||
</MultiStepFormElement>
|
</MultiStepFormElement>
|
||||||
{!serverSettings.other_relays_enabled && (
|
{!serverSettings.otherRelaysEnabled && (
|
||||||
<DetectEmailAutofillService
|
<DetectEmailAutofillService
|
||||||
domains={serverSettings.other_relay_domains}
|
domains={serverSettings.otherRelayDomains}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
@ -28,14 +28,14 @@ export default function VerifyEmailRoute(): ReactElement {
|
|||||||
|
|
||||||
const tokenSchema = yup
|
const tokenSchema = yup
|
||||||
.string()
|
.string()
|
||||||
.length(serverSettings.email_verification_length)
|
.length(serverSettings.emailVerificationLength)
|
||||||
.test("token", "Invalid token", token => {
|
.test("token", "Invalid token", token => {
|
||||||
if (!token) {
|
if (!token) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check token only contains chars from `serverSettings.email_verification_chars`
|
// Check token only contains chars from `serverSettings.email_verification_chars`
|
||||||
const chars = serverSettings.email_verification_chars.split("")
|
const chars = serverSettings.emailVerificationChars.split("")
|
||||||
|
|
||||||
return token.split("").every(char => chars.includes(char))
|
return token.split("").every(char => chars.includes(char))
|
||||||
})
|
})
|
||||||
|
@ -27,9 +27,18 @@ export enum Theme {
|
|||||||
DARK = "dark",
|
DARK = "dark",
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface User {
|
export enum ThemeSettings {
|
||||||
|
LIGHT = "light",
|
||||||
|
DARK = "dark",
|
||||||
|
SYSTEM = "system",
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ServerUser {
|
||||||
id: string
|
id: string
|
||||||
createdAt: Date
|
createdAt: Date
|
||||||
|
encryptedNotes: string
|
||||||
|
isDecrypted: false
|
||||||
|
encryptedPassword: string
|
||||||
email: {
|
email: {
|
||||||
address: string
|
address: string
|
||||||
isVerified: boolean
|
isVerified: boolean
|
||||||
@ -44,21 +53,21 @@ export interface User {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface AuthenticationDetails {
|
export interface AuthenticationDetails {
|
||||||
user: User
|
user: ServerUser
|
||||||
detail: string
|
detail: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ServerSettings {
|
export interface ServerSettings {
|
||||||
mail_domain: string
|
mailDomain: string
|
||||||
random_email_id_min_length: number
|
randomEmailIdMinLength: number
|
||||||
random_email_id_chars: string
|
RandomEmailIdChars: string
|
||||||
image_proxy_enabled: boolean
|
imageProxyEnabled: boolean
|
||||||
image_proxy_life_time: number
|
imageProxyLifeTime: number
|
||||||
disposable_emails_enabled: boolean
|
disposableEmailsEnabled: boolean
|
||||||
other_relays_enabled: boolean
|
otherRelaysEnabled: boolean
|
||||||
other_relay_domains: Array<string>
|
otherRelayDomains: Array<string>
|
||||||
email_verification_chars: string
|
emailVerificationChars: string
|
||||||
email_verification_length: number
|
emailVerificationLength: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MinimumServerResponse {
|
export interface MinimumServerResponse {
|
||||||
@ -82,3 +91,9 @@ export interface UserNote {
|
|||||||
theme: Theme
|
theme: Theme
|
||||||
privateKey: string
|
privateKey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface User
|
||||||
|
extends Omit<ServerUser, "encryptedNotes" | "isDecrypted"> {
|
||||||
|
notes: UserNote
|
||||||
|
isDecrypted: true
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import Crypto from "crypto-js"
|
import Crypto from "crypto-js"
|
||||||
|
|
||||||
export default function decryptString(value: string, password: string): string {
|
export default function decryptString(value: string, password: string): string {
|
||||||
return Crypto.AES.decrypt(value, password).toString(Crypto.enc.Utf8)
|
return Crypto.AES.decrypt(value, password).toString()
|
||||||
}
|
}
|
||||||
|
@ -10,16 +10,6 @@ export const USER_NOTE_SCHEMA = yup.object().shape({
|
|||||||
theme: yup.string().oneOf(Object.values(Theme)).required(),
|
theme: yup.string().oneOf(Object.values(Theme)).required(),
|
||||||
})
|
})
|
||||||
|
|
||||||
export function createUserNote(
|
|
||||||
privateKey: string,
|
|
||||||
theme: Theme = Theme.LIGHT,
|
|
||||||
): UserNote {
|
|
||||||
return {
|
|
||||||
theme,
|
|
||||||
privateKey,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function decryptUserNote(
|
export function decryptUserNote(
|
||||||
encryptedUserNote: string,
|
encryptedUserNote: string,
|
||||||
password: string,
|
password: string,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user