Compare commits

...

2 Commits

Author SHA1 Message Date
Yury
819902eafb chore: fixed code formatting 2024-05-15 11:50:21 +03:00
Yury
4e7f9d650e feat: changed MIME type of the uploaded file to sigit 2024-05-15 11:41:10 +03:00
18 changed files with 126 additions and 114 deletions

7
.prettierrc Normal file
View File

@ -0,0 +1,7 @@
{
"trailingComma": "none",
"tabWidth": 2,
"semi": false,
"singleQuote": true,
"endOfLine": "auto"
}

View File

@ -9,6 +9,8 @@
"build": "tsc && vite build",
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"lint:fix": "eslint . --fix --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"formatter:check": "npx prettier --check \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
"formatter:fix": "npx prettier --write \"src/**/*.{ts,tsx,js,jsx,html,css,sass,less,yml,md,graphql}\"",
"preview": "vite preview"
},
"dependencies": {

View File

@ -67,7 +67,7 @@ const App = () => {
})}
<Route
path='*'
path="*"
element={
<Navigate
to={

View File

@ -87,10 +87,10 @@ export const AppBar = () => {
const isAuthenticated = authState?.loggedIn === true
return (
<AppBarMui position='fixed' className={styles.AppBar}>
<AppBarMui position="fixed" className={styles.AppBar}>
<Toolbar className={styles.toolbar}>
<Box className={styles.logoWrapper}>
<img src='/logo.png' alt='Logo' onClick={() => navigate('/')} />
<img src="/logo.png" alt="Logo" onClick={() => navigate('/')} />
</Box>
<Box className={styles.rightSideBox}>
@ -99,7 +99,7 @@ export const AppBar = () => {
onClick={() => {
navigate(appPublicRoutes.login)
}}
variant='contained'
variant="contained"
>
Sign in
</Button>
@ -113,7 +113,7 @@ export const AppBar = () => {
handleClick={handleOpenUserMenu}
/>
<Menu
id='menu-appbar'
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: 'bottom',
@ -133,7 +133,7 @@ export const AppBar = () => {
display: { md: 'none' }
}}
>
<Typography variant='h6'>{username}</Typography>
<Typography variant="h6">{username}</Typography>
</MenuItem>
<MenuItem
onClick={handleProfile}
@ -145,7 +145,7 @@ export const AppBar = () => {
</MenuItem>
<Link
to={appPublicRoutes.help}
target='_blank'
target="_blank"
style={{ color: 'inherit', textDecoration: 'inherit' }}
>
<MenuItem

View File

@ -13,16 +13,16 @@ const Username = ({ username, avatarContent, handleClick }: Props) => {
return (
<IconButton
aria-label='account of current user'
aria-controls='menu-appbar'
aria-haspopup='true'
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleClick}
color='inherit'
color="inherit"
>
<img
src={avatarContent}
alt='user-avatar'
className='profile-image'
alt="user-avatar"
className="profile-image"
style={{
borderWidth: '3px',
borderStyle: hexKey ? 'solid' : 'none',
@ -30,7 +30,7 @@ const Username = ({ username, avatarContent, handleClick }: Props) => {
}}
/>
<Typography
variant='h6'
variant="h6"
sx={{
color: '#3e3e3e',
padding: '0 8px',

View File

@ -152,9 +152,8 @@ export class MetadataController {
created_at: timestamp
}
signedMetadataEvent = await this.nostrController.signEvent(
newMetadataEvent
)
signedMetadataEvent =
await this.nostrController.signEvent(newMetadataEvent)
}
await this.nostrController
@ -222,9 +221,8 @@ export class MetadataController {
}
// sign job request event
const jobSignedEvent = await this.nostrController.signEvent(
jobEventTemplate
)
const jobSignedEvent =
await this.nostrController.signEvent(jobEventTemplate)
const relays = [
'wss://relay.damus.io',

View File

@ -219,12 +219,10 @@ export class NostrController extends EventEmitter {
results.forEach((res, index) => {
if (res.status === 'rejected') {
failedPublishes.push(
{
relay: relays[index],
error: res.reason.message
}
)
failedPublishes.push({
relay: relays[index],
error: res.reason.message
})
}
})

View File

@ -59,13 +59,13 @@ export const MainLayout = () => {
setIsLoading(false)
}, [dispatch])
if (isLoading) return <LoadingSpinner desc='Loading App' />
if (isLoading) return <LoadingSpinner desc="Loading App" />
return (
<>
<AppBar />
<Box className='main'>
<Box className="main">
<Container
sx={{
position: 'relative',

View File

@ -93,7 +93,7 @@ export const DecryptZip = () => {
<>
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
<Box className={styles.container}>
<Typography component='label' variant='h6'>
<Typography component="label" variant="h6">
Select encrypted zip file
</Typography>
@ -104,11 +104,11 @@ export const DecryptZip = () => {
>
{isDraggingOver && (
<Box className={styles.fileDragOver}>
<Typography variant='body1'>Drop file here</Typography>
<Typography variant="body1">Drop file here</Typography>
</Box>
)}
<MuiFileInput
placeholder='Drop file here, or click to select'
placeholder="Drop file here, or click to select"
value={selectedFile}
onChange={(value) => setSelectedFile(value)}
InputProps={{
@ -119,8 +119,8 @@ export const DecryptZip = () => {
/>
<TextField
label='Encryption Key'
variant='outlined'
label="Encryption Key"
variant="outlined"
value={encryptionKey}
onChange={(e) => setEncryptionKey(e.target.value)}
/>
@ -129,7 +129,7 @@ export const DecryptZip = () => {
<Box sx={{ mt: 1, display: 'flex', justifyContent: 'center' }}>
<Button
onClick={handleDecrypt}
variant='contained'
variant="contained"
disabled={!selectedFile || !encryptionKey}
>
Decrypt

View File

@ -10,13 +10,13 @@ export const HomePage = () => {
<Box className={styles.container}>
<Button
onClick={() => navigate(appPrivateRoutes.sign)}
variant='contained'
variant="contained"
>
Sign
</Button>
<Button
onClick={() => navigate(appPrivateRoutes.verify)}
variant='contained'
variant="contained"
>
Verify
</Button>

View File

@ -57,7 +57,7 @@ export const LandingPage = () => {
? theme.palette.getContrastText(bodyBackgroundColor)
: ''
}}
variant='h4'
variant="h4"
>
What is Nostr?
</Typography>
@ -67,14 +67,14 @@ export const LandingPage = () => {
? theme.palette.getContrastText(bodyBackgroundColor)
: ''
}}
variant='body1'
variant="body1"
>
Nostr is a decentralised messaging protocol where YOU own your
identity. To get started, you must have an existing{' '}
<a
className='bold-link'
target='_blank'
href='https://nostr.com/'
className="bold-link"
target="_blank"
href="https://nostr.com/"
>
Nostr account
</a>
@ -95,7 +95,7 @@ export const LandingPage = () => {
<div className={styles.loginBottomBar}>
<Button
className={styles.loginBtn}
variant='contained'
variant="contained"
onClick={onSignInClick}
>
GET STARTED

View File

@ -53,9 +53,8 @@ export const Login = () => {
dispatch(updateLoginMethod(LoginMethods.extension))
setLoadingSpinnerDesc('Authenticating and finding metadata')
const redirectPath = await authController.authenticateAndFindMetadata(
pubkey
)
const redirectPath =
await authController.authenticateAndFindMetadata(pubkey)
navigate(redirectPath)
})
@ -290,10 +289,10 @@ export const Login = () => {
if (authUrl) {
return (
<iframe
title='Nsecbunker auth'
title="Nsecbunker auth"
src={authUrl}
width='100%'
height='500px'
width="100%"
height="500px"
/>
)
}
@ -302,21 +301,21 @@ export const Login = () => {
<>
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
<div className={styles.loginPage}>
<Typography variant='h4'>Welcome to Sigit</Typography>
<Typography variant="h4">Welcome to Sigit</Typography>
<TextField
label='nip05 / npub / nsec / bunker connx string'
label="nip05 / npub / nsec / bunker connx string"
value={inputValue}
onChange={(e) => setInputValue(e.target.value)}
sx={{ width: '100%', mt: 2 }}
/>
{isNostrExtensionAvailable && (
<Button onClick={loginWithExtension} variant='text'>
<Button onClick={loginWithExtension} variant="text">
Login with extension
</Button>
)}
<Box sx={{ mt: 1, display: 'flex', justifyContent: 'center' }}>
<Button disabled={!inputValue} onClick={login} variant='contained'>
<Button disabled={!inputValue} onClick={login} variant="contained">
Login
</Button>
</Box>

View File

@ -127,7 +127,7 @@ export const ProfilePage = () => {
label={label}
id={label.split(' ').join('-')}
value={profileMetadata![key] || ''}
size='small'
size="small"
multiline={multiline}
rows={rows}
className={styles.textField}
@ -166,7 +166,7 @@ export const ProfilePage = () => {
label={label}
id={label.split(' ').join('-')}
defaultValue={value}
size='small'
size="small"
className={styles.textField}
disabled
type={isPassword ? 'password' : 'text'}
@ -230,18 +230,23 @@ export const ProfilePage = () => {
}
/**
*
*
* @returns robohash generate button, loading spinner or no button
*/
const robohashButton = () => {
if (profileMetadata?.picture?.includes('robohash')) return null
if (profileMetadata?.picture?.includes('robohash')) return null
return <Tooltip title="Generate a robohash avatar">
{avatarLoading ? <CircularProgress style={{padding: 8}} size={22}/>
: <IconButton onClick={generateRobotAvatar}>
<SmartToy/>
</IconButton>}
</Tooltip>
return (
<Tooltip title="Generate a robohash avatar">
{avatarLoading ? (
<CircularProgress style={{ padding: 8 }} size={22} />
) : (
<IconButton onClick={generateRobotAvatar}>
<SmartToy />
</IconButton>
)}
</Tooltip>
)
}
return (
@ -284,7 +289,7 @@ export const ProfilePage = () => {
}}
className={styles.img}
src={profileMetadata.picture || placeholderAvatar}
alt='Profile Image'
alt="Profile Image"
/>
{nostrJoiningBlock && (
@ -296,7 +301,7 @@ export const ProfilePage = () => {
}}
component={Link}
to={`https://njump.me/${nostrJoiningBlock.encodedEventPointer}`}
target='_blank'
target="_blank"
>
On nostr since {nostrJoiningBlock.block.toLocaleString()}
</Typography>
@ -333,7 +338,7 @@ export const ProfilePage = () => {
{isUsersOwnProfile && (
<LoadingButton
loading={savingProfileMetadata}
variant='contained'
variant="contained"
onClick={handleSaveMetadata}
>
SAVE

View File

@ -336,10 +336,10 @@ export const SignPage = () => {
if (authUrl) {
return (
<iframe
title='Nsecbunker auth'
title="Nsecbunker auth"
src={authUrl}
width='100%'
height='500px'
width="100%"
height="500px"
/>
)
}
@ -348,13 +348,13 @@ export const SignPage = () => {
<>
{isLoading && <LoadingSpinner desc={loadingSpinnerDesc} />}
<Box className={styles.container}>
<Typography component='label' variant='h6'>
<Typography component="label" variant="h6">
Select files
</Typography>
<MuiFileInput
multiple
placeholder='Choose Files'
placeholder="Choose Files"
value={selectedFiles}
onChange={(value) => handleSelectFiles(value)}
/>
@ -362,7 +362,7 @@ export const SignPage = () => {
<ul>
{selectedFiles.map((file, index) => (
<li key={index}>
<Typography component='label'>{file.name}</Typography>
<Typography component="label">{file.name}</Typography>
<IconButton onClick={() => handleRemoveFile(file)}>
<Clear style={{ color: 'red' }} />{' '}
</IconButton>
@ -372,24 +372,24 @@ export const SignPage = () => {
{displayUserInput && (
<>
<Typography component='label' variant='h6'>
<Typography component="label" variant="h6">
Select signers and viewers
</Typography>
<Box className={styles.inputBlock}>
<TextField
label='nip05 / npub'
label="nip05 / npub"
value={userInput}
onChange={(e) => setUserInput(e.target.value)}
helperText={error}
error={!!error}
/>
<FormControl fullWidth>
<InputLabel id='select-role-label'>Role</InputLabel>
<InputLabel id="select-role-label">Role</InputLabel>
<Select
labelId='select-role-label'
id='demo-simple-select'
labelId="select-role-label"
id="demo-simple-select"
value={userRole}
label='Role'
label="Role"
onChange={(e) => setUserRole(e.target.value as UserRole)}
>
<MenuItem value={UserRole.signer}>{UserRole.signer}</MenuItem>
@ -401,7 +401,7 @@ export const SignPage = () => {
<Button
disabled={!userInput}
onClick={handleAddUser}
variant='contained'
variant="contained"
>
Add
</Button>
@ -413,7 +413,7 @@ export const SignPage = () => {
handleRemoveUser={handleRemoveUser}
/>
<Box sx={{ mt: 1, display: 'flex', justifyContent: 'center' }}>
<Button onClick={handleSign} variant='contained'>
<Button onClick={handleSign} variant="contained">
Sign
</Button>
</Box>
@ -491,8 +491,8 @@ const DisplayUser = ({
<img
onError={imageLoadError}
src={userMeta?.picture || roboUrl}
alt='Profile Image'
className='profile-image'
alt="Profile Image"
className="profile-image"
style={{
borderWidth: '3px',
borderStyle: 'solid',
@ -500,7 +500,7 @@ const DisplayUser = ({
}}
/>
<Link to={getProfileRoute(user.pubkey)}>
<Typography component='label' className={styles.name}>
<Typography component="label" className={styles.name}>
{userMeta?.display_name ||
userMeta?.name ||
shorten(npub)}
@ -525,7 +525,7 @@ const DisplayUser = ({
</Select>
</TableCell>
<TableCell>
<Tooltip title='Remove User' arrow>
<Tooltip title="Remove User" arrow>
<IconButton onClick={() => handleRemoveUser(user.pubkey)}>
<Clear style={{ color: 'red' }} />
</IconButton>

View File

@ -455,10 +455,10 @@ export const VerifyPage = () => {
if (authUrl) {
return (
<iframe
title='Nsecbunker auth'
title="Nsecbunker auth"
src={authUrl}
width='100%'
height='500px'
width="100%"
height="500px"
/>
)
}
@ -469,13 +469,13 @@ export const VerifyPage = () => {
<Box className={styles.container}>
{displayInput && (
<>
<Typography component='label' variant='h6'>
<Typography component="label" variant="h6">
Select sigit file
</Typography>
<Box className={styles.inputBlock}>
<MuiFileInput
placeholder='Select file'
placeholder="Select file"
value={selectedFile}
onChange={(value) => setSelectedFile(value)}
InputProps={{
@ -487,8 +487,8 @@ export const VerifyPage = () => {
{selectedFile && (
<TextField
label='Encryption Key'
variant='outlined'
label="Encryption Key"
variant="outlined"
value={encryptionKey}
onChange={(e) => setEncryptionKey(e.target.value)}
/>
@ -497,7 +497,7 @@ export const VerifyPage = () => {
{selectedFile && encryptionKey && (
<Box sx={{ mt: 2, display: 'flex', justifyContent: 'center' }}>
<Button onClick={handleDecrypt} variant='contained'>
<Button onClick={handleDecrypt} variant="contained">
Decrypt
</Button>
</Box>
@ -509,7 +509,7 @@ export const VerifyPage = () => {
<>
<DisplayMeta meta={meta} nextSigner={nextSinger} />
<Box sx={{ mt: 1, display: 'flex', justifyContent: 'center' }}>
<Button onClick={handleExport} variant='contained'>
<Button onClick={handleExport} variant="contained">
Export
</Button>
</Box>
@ -524,7 +524,7 @@ export const VerifyPage = () => {
<>
<DisplayMeta meta={meta} nextSigner={nextSinger} />
<Box sx={{ mt: 1, display: 'flex', justifyContent: 'center' }}>
<Button onClick={handleSign} variant='contained'>
<Button onClick={handleSign} variant="contained">
Sign
</Button>
</Box>
@ -661,7 +661,7 @@ const DisplayMeta = ({ meta, nextSigner }: DisplayMetaProps) => {
gap: '15px'
}}
>
<Typography variant='h6' sx={{ color: textColor }}>
<Typography variant="h6" sx={{ color: textColor }}>
Submitted By
</Typography>
<Box className={styles.user}>
@ -671,8 +671,8 @@ const DisplayMeta = ({ meta, nextSigner }: DisplayMetaProps) => {
metadata[meta.submittedBy]?.picture ||
getRoboImageUrl(meta.submittedBy)
}
alt='Profile Image'
className='profile-image'
alt="Profile Image"
className="profile-image"
style={{
borderWidth: '3px',
borderStyle: 'solid',
@ -680,7 +680,7 @@ const DisplayMeta = ({ meta, nextSigner }: DisplayMetaProps) => {
}}
/>
<Link to={getProfileRoute(meta.submittedBy)}>
<Typography component='label' className={styles.name}>
<Typography component="label" className={styles.name}>
{metadata[meta.submittedBy]?.display_name ||
metadata[meta.submittedBy]?.name ||
shorten(hexToNpub(meta.submittedBy))}
@ -695,7 +695,7 @@ const DisplayMeta = ({ meta, nextSigner }: DisplayMetaProps) => {
alignItems: 'flex-start'
}}
>
<Typography variant='h6' sx={{ color: textColor }}>
<Typography variant="h6" sx={{ color: textColor }}>
Files
</Typography>
<ul>
@ -741,8 +741,8 @@ const DisplayMeta = ({ meta, nextSigner }: DisplayMetaProps) => {
<img
onError={imageLoadError}
src={userMeta?.picture || roboUrl}
alt='Profile Image'
className='profile-image'
alt="Profile Image"
className="profile-image"
style={{
borderWidth: '3px',
borderStyle: 'solid',
@ -750,7 +750,7 @@ const DisplayMeta = ({ meta, nextSigner }: DisplayMetaProps) => {
}}
/>
<Link to={getProfileRoute(user.pubkey)}>
<Typography component='label' className={styles.name}>
<Typography component="label" className={styles.name}>
{userMeta?.display_name ||
userMeta?.name ||
shorten(npub)}

View File

@ -1,20 +1,21 @@
export class DecryptionError extends Error {
public message: string = ''
constructor(
public inputError: any
) {
constructor(public inputError: any) {
super()
if (inputError.message.toLowerCase().includes('expected')) {
this.message = `The decryption key length or format is invalid.`
} else if (inputError.message.includes('The JWK "alg" member was inconsistent')) {
} else if (
inputError.message.includes('The JWK "alg" member was inconsistent')
) {
this.message = `The decryption key is invalid.`
} else {
this.message = inputError.message || 'An error occurred while decrypting file.'
this.message =
inputError.message || 'An error occurred while decrypting file.'
}
this.name = 'DecryptionError'
Object.setPrototypeOf(this, DecryptionError.prototype)
}
}
}

View File

@ -66,14 +66,14 @@ export const decryptArrayBuffer = async (
) => {
try {
const { cryptoKey, iv } = await importKey(key)
// Decrypt the data
const decryptedData = await window.crypto.subtle.decrypt(
{ name: ENCRYPTION_ALGO_NAME, iv },
cryptoKey,
encryptedData
)
return decryptedData
} catch (err) {
throw new DecryptionError(err)

View File

@ -18,8 +18,8 @@ export const uploadToFileStorage = async (
const unixNow = Math.floor(Date.now() / 1000)
// Create a File object with the Blob data
const file = new File([blob], `zipped-${unixNow}.zip`, {
type: 'application/zip'
const file = new File([blob], `compressed-${unixNow}.sigit`, {
type: 'application/sigit'
})
// Define event metadata for authorization
@ -39,13 +39,13 @@ export const uploadToFileStorage = async (
const authEvent = await nostrController.signEvent(event)
// URL of the file storage service
const FILE_STORAGE_URL = 'https://blossom.sigit.io'
const FILE_STORAGE_URL = 'https://blossom.sigit.io' // REFACTOR: should be an env
// Upload the file to the file storage service using Axios
const response = await axios.put(`${FILE_STORAGE_URL}/upload`, file, {
headers: {
Authorization: 'Nostr ' + btoa(JSON.stringify(authEvent)), // Set authorization header
'Content-Type': 'application/zip' // Set content type header
'Content-Type': 'application/sigit' // Set content type header
}
})
@ -166,7 +166,9 @@ export const sendDM = async (
toast.error('An error occurred while publishing DM')
errResults.forEach((errResult: any) => {
toast.error(`Publishing to ${errResult.relay} caused the following error: ${errResult.error}`)
toast.error(
`Publishing to ${errResult.relay} caused the following error: ${errResult.error}`
)
})
return null