Compare commits
No commits in common. "66ff214024a89b731b6fc61a58e3ef276352a86a" and "4119ee870e925243da6e8b31d2d4991211d0f90a" have entirely different histories.
66ff214024
...
4119ee870e
9 changed files with 71 additions and 140 deletions
|
|
@ -12,6 +12,7 @@
|
||||||
"@kobalte/core": "^0.13.11",
|
"@kobalte/core": "^0.13.11",
|
||||||
"@solidjs-use/integrations": "^2.3.0",
|
"@solidjs-use/integrations": "^2.3.0",
|
||||||
"@solidjs/router": "^0.15.3",
|
"@solidjs/router": "^0.15.3",
|
||||||
|
"bcryptjs": "^3.0.2",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
"dayjs": "^1.11.18",
|
"dayjs": "^1.11.18",
|
||||||
"gsap": "^3.13.0",
|
"gsap": "^3.13.0",
|
||||||
|
|
@ -23,7 +24,6 @@
|
||||||
"solidjs-use": "^2.3.0"
|
"solidjs-use": "^2.3.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nanostores/solid": "^1.1.1",
|
|
||||||
"@types/crypto-js": "^4.2.2",
|
"@types/crypto-js": "^4.2.2",
|
||||||
"sass-embedded": "^1.93.2",
|
"sass-embedded": "^1.93.2",
|
||||||
"typescript": "~5.8.3",
|
"typescript": "~5.8.3",
|
||||||
|
|
|
||||||
23
pnpm-lock.yaml
generated
23
pnpm-lock.yaml
generated
|
|
@ -17,6 +17,9 @@ importers:
|
||||||
'@solidjs/router':
|
'@solidjs/router':
|
||||||
specifier: ^0.15.3
|
specifier: ^0.15.3
|
||||||
version: 0.15.3(solid-js@1.9.9)
|
version: 0.15.3(solid-js@1.9.9)
|
||||||
|
bcryptjs:
|
||||||
|
specifier: ^3.0.2
|
||||||
|
version: 3.0.2
|
||||||
crypto-js:
|
crypto-js:
|
||||||
specifier: ^4.2.0
|
specifier: ^4.2.0
|
||||||
version: 4.2.0
|
version: 4.2.0
|
||||||
|
|
@ -45,9 +48,6 @@ importers:
|
||||||
specifier: ^2.3.0
|
specifier: ^2.3.0
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
devDependencies:
|
devDependencies:
|
||||||
'@nanostores/solid':
|
|
||||||
specifier: ^1.1.1
|
|
||||||
version: 1.1.1(nanostores@1.0.1)(solid-js@1.9.9)
|
|
||||||
'@types/crypto-js':
|
'@types/crypto-js':
|
||||||
specifier: ^4.2.2
|
specifier: ^4.2.2
|
||||||
version: 4.2.2
|
version: 4.2.2
|
||||||
|
|
@ -481,12 +481,6 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
solid-js: ^1.8.8
|
solid-js: ^1.8.8
|
||||||
|
|
||||||
'@nanostores/solid@1.1.1':
|
|
||||||
resolution: {integrity: sha512-gF0Eat1/c3hOaklBMSVoEjcNzJc5zGk4VSg94H9LPmXYww1pxgr7zylpi3jjyxRu24c8+aYNkmRWzolAwzSA1A==}
|
|
||||||
peerDependencies:
|
|
||||||
nanostores: '>=0.9.0 <2.0.0'
|
|
||||||
solid-js: ^1.6.0
|
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.1':
|
'@parcel/watcher-android-arm64@2.5.1':
|
||||||
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
|
resolution: {integrity: sha512-KF8+j9nNbUN8vzOFDpRMsaKBHZ/mcjEjMToVMJOhTozkDonQFFrRcfdLWn6yWKCmJKmdVxSgHiYvTCef4/qcBA==}
|
||||||
engines: {node: '>= 10.0.0'}
|
engines: {node: '>= 10.0.0'}
|
||||||
|
|
@ -834,6 +828,10 @@ packages:
|
||||||
resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==}
|
resolution: {integrity: sha512-wrH5NNqren/QMtKUEEJf7z86YjfqW/2uw3IL3/xpqZUC95SSVIFXYQeeGjL6FT/X68IROu6RMehZQS5foy2BXw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
|
bcryptjs@3.0.2:
|
||||||
|
resolution: {integrity: sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
braces@3.0.3:
|
braces@3.0.3:
|
||||||
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -1761,11 +1759,6 @@ snapshots:
|
||||||
'@solid-primitives/utils': 6.3.2(solid-js@1.9.9)
|
'@solid-primitives/utils': 6.3.2(solid-js@1.9.9)
|
||||||
solid-js: 1.9.9
|
solid-js: 1.9.9
|
||||||
|
|
||||||
'@nanostores/solid@1.1.1(nanostores@1.0.1)(solid-js@1.9.9)':
|
|
||||||
dependencies:
|
|
||||||
nanostores: 1.0.1
|
|
||||||
solid-js: 1.9.9
|
|
||||||
|
|
||||||
'@parcel/watcher-android-arm64@2.5.1':
|
'@parcel/watcher-android-arm64@2.5.1':
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|
@ -2026,6 +2019,8 @@ snapshots:
|
||||||
|
|
||||||
baseline-browser-mapping@2.8.6: {}
|
baseline-browser-mapping@2.8.6: {}
|
||||||
|
|
||||||
|
bcryptjs@3.0.2: {}
|
||||||
|
|
||||||
braces@3.0.3:
|
braces@3.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
fill-range: 7.1.1
|
fill-range: 7.1.1
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,11 @@
|
||||||
import './File.sass'
|
import './File.sass'
|
||||||
import { FileField } from '@kobalte/core/file-field'
|
import { FileField } from '@kobalte/core/file-field'
|
||||||
|
|
||||||
interface Props {
|
export default () => {
|
||||||
maxFiles: number
|
|
||||||
accept: string
|
|
||||||
onFileAccept?: (files: File[]) => void
|
|
||||||
label: string
|
|
||||||
buttonText: string
|
|
||||||
onClick: () => void
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (props: Props) => {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FileField class="filefield" maxFiles={props.maxFiles} onFileAccept={props.onFileAccept} accept={props.accept}>
|
<FileField class="filefield" maxFiles={1} onFileAccept={(data) => console.log('data', data)} onFileReject={(data) => console.log('data', data)} onFileChange={(data) => console.log('data', data)}>
|
||||||
<FileField.Dropzone class="filefield__dropzone">{props.label}</FileField.Dropzone>
|
<FileField.Dropzone class="filefield__dropzone">Drag and drop or click to upload file</FileField.Dropzone>
|
||||||
<FileField.HiddenInput />
|
<FileField.HiddenInput />
|
||||||
<FileField.ItemList class="filefield__itemList">
|
<FileField.ItemList class="filefield__itemList">
|
||||||
{() => (
|
{() => (
|
||||||
|
|
@ -22,9 +13,7 @@ export default (props: Props) => {
|
||||||
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
|
<FileField.ItemPreviewImage class="filefield__itemPreviewImage" />
|
||||||
<FileField.ItemName class="filefield__itemName" />
|
<FileField.ItemName class="filefield__itemName" />
|
||||||
<FileField.ItemSize class="filefield__itemSize" />
|
<FileField.ItemSize class="filefield__itemSize" />
|
||||||
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger" onClick={props.onClick}>
|
<FileField.ItemDeleteTrigger class="filefield__itemDeleteTrigger">Delete</FileField.ItemDeleteTrigger>
|
||||||
{props.buttonText}
|
|
||||||
</FileField.ItemDeleteTrigger>
|
|
||||||
</FileField.Item>
|
</FileField.Item>
|
||||||
)}
|
)}
|
||||||
</FileField.ItemList>
|
</FileField.ItemList>
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,52 @@
|
||||||
import './Modal.sass'
|
import './Modal.sass'
|
||||||
import { type JSXElement, Show } from 'solid-js'
|
import { type JSXElement, Show } from 'solid-js'
|
||||||
|
import gsap from 'gsap'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: JSXElement
|
children: JSXElement
|
||||||
background?: string
|
background?: string
|
||||||
color?: string
|
color?: string
|
||||||
border?: string
|
border?: string
|
||||||
|
trigger: boolean
|
||||||
opacity?: number
|
opacity?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (props: Props) => {
|
export default (props: Props) => {
|
||||||
|
let dialogRef!: HTMLDivElement
|
||||||
|
|
||||||
|
// const openHandler = () => {
|
||||||
|
// gsap.to(dialogRef, {
|
||||||
|
// duration: 0,
|
||||||
|
// display: 'flex',
|
||||||
|
// ease: 'power2.out',
|
||||||
|
// })
|
||||||
|
// }
|
||||||
|
|
||||||
|
const closeHandler = () => {
|
||||||
|
gsap.to(dialogRef, {
|
||||||
|
duration: 0,
|
||||||
|
display: 'none',
|
||||||
|
ease: 'power2.out',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div class="modal">
|
<Show when={props.trigger}>
|
||||||
<Show when={props.border}>
|
<div class="modal" ref={dialogRef} onClick={closeHandler}>
|
||||||
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; border: 2px solid ${props.border}; opacity: ${props.opacity || 1}`}>
|
<Show when={props.border}>
|
||||||
{props.children}
|
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; border: 2px solid ${props.border}; opacity: ${props.opacity || 1}`}>
|
||||||
</div>
|
{props.children}
|
||||||
</Show>
|
</div>
|
||||||
|
</Show>
|
||||||
|
|
||||||
<Show when={!props.border}>
|
<Show when={!props.border}>
|
||||||
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; opacity: ${props.opacity || 1}; box-shadow: 5px 4px 6px rgba(0, 0, 0, 0.5)`}>
|
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; opacity: ${props.opacity || 1}; box-shadow: 5px 4px 6px rgba(0, 0, 0, 0.5)`}>
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
</Show>
|
</Show>
|
||||||
</div>
|
</div>
|
||||||
|
</Show>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,51 +0,0 @@
|
||||||
import './Modal.sass'
|
|
||||||
import { type JSXElement, Show, createSignal } from 'solid-js'
|
|
||||||
import Button from '../Button/Button'
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
children: JSXElement
|
|
||||||
background?: string
|
|
||||||
color?: string
|
|
||||||
border?: string
|
|
||||||
opacity?: number
|
|
||||||
label: string
|
|
||||||
edges?: 'curved' | 'rounded' | 'flat'
|
|
||||||
design?: 'bu-primary' | 'bu-link' | 'bu-info' | 'bu-success' | 'bu-warning' | 'bu-danger' | 'bu-dark' | 'bu-light' | 'bu-text' | 'bu-ghost' | 'bo-primary' | 'bo-secondary' | 'bo-success' | 'bo-danger' | 'bo-warning' | 'bo-info' | 'bo-light' | 'bo-dark' | 'bo-link'
|
|
||||||
width?: number
|
|
||||||
wide?: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
export default (props: Props) => {
|
|
||||||
const [isOpen, setIsOpen] = createSignal(false)
|
|
||||||
|
|
||||||
const openHandler = () => {
|
|
||||||
setIsOpen(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
const closeHandler = () => {
|
|
||||||
setIsOpen(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<Show when={!isOpen()}>
|
|
||||||
<Button label={props.label} edges={props.edges} design={props.design} onClick={openHandler} />
|
|
||||||
</Show>
|
|
||||||
<Show when={isOpen()}>
|
|
||||||
<div class="modal" onClick={closeHandler}>
|
|
||||||
<Show when={props.border}>
|
|
||||||
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; border: 2px solid ${props.border}; opacity: ${props.opacity || 1}`}>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={!props.border}>
|
|
||||||
<div class="modal__content" style={`background-color: ${props.background}; color: ${props.color}; opacity: ${props.opacity || 1}; box-shadow: 5px 4px 6px rgba(0, 0, 0, 0.5)`}>
|
|
||||||
{props.children}
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</div>
|
|
||||||
</Show>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -14,7 +14,6 @@ export { default as Row } from './Row/Row'
|
||||||
export { default as Display } from './Display/Display'
|
export { default as Display } from './Display/Display'
|
||||||
export { default as Padding } from './Padding/Padding'
|
export { default as Padding } from './Padding/Padding'
|
||||||
export { default as Modal } from './Modal/Modal'
|
export { default as Modal } from './Modal/Modal'
|
||||||
export { default as ModalButton } from './Modal/ModalButton'
|
|
||||||
export { default as Table } from './Table/Table'
|
export { default as Table } from './Table/Table'
|
||||||
export { default as Combobox } from './Combobox/Combobox'
|
export { default as Combobox } from './Combobox/Combobox'
|
||||||
export { default as File } from './File/File'
|
export { default as File } from './File/File'
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,6 @@
|
||||||
@use 'sass:color'
|
|
||||||
|
|
||||||
.box-title
|
.box-title
|
||||||
font-size: 1.75rem
|
font-size: 1.75rem
|
||||||
font-weight: 700
|
font-weight: 700
|
||||||
|
|
||||||
.approver-name
|
.approver-name
|
||||||
font-size: 1.25rem
|
font-size: 1.25rem
|
||||||
|
|
||||||
.required
|
|
||||||
padding: 1rem
|
|
||||||
border-radius: 8px
|
|
||||||
background-color: color.adjust(#0D64E4, $blackness: 20%)
|
|
||||||
opacity: 0.6
|
|
||||||
width: 100%
|
|
||||||
text-align: center
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import './Login.sass'
|
import './Login.sass'
|
||||||
import { Logo, Link, Page, Row, Padding, Box, Radio, Combobox, Input, Button } from '../../components'
|
import { Logo, Link, Page, Row, Padding, Form, Box, Radio, Combobox, Input, Button, Modal } from '../../components'
|
||||||
import { IoChevronBack } from 'solid-icons/io'
|
import { IoChevronBack } from 'solid-icons/io'
|
||||||
import { createSignal, Show, createEffect } from 'solid-js'
|
import { createSignal, Show } from 'solid-js'
|
||||||
import { ofetch } from 'ofetch'
|
import { ofetch } from 'ofetch'
|
||||||
import { SHA1, SHA3 } from 'crypto-js'
|
import { SHA1, SHA3 } from 'crypto-js'
|
||||||
import { useNavigate } from '@solidjs/router'
|
import { useNavigate } from '@solidjs/router'
|
||||||
|
|
@ -9,12 +9,13 @@ import { useNavigate } from '@solidjs/router'
|
||||||
export default () => {
|
export default () => {
|
||||||
const API = import.meta.env.VITE_BACKEND
|
const API = import.meta.env.VITE_BACKEND
|
||||||
const APPROVERNAME = import.meta.env.VITE_HEAD
|
const APPROVERNAME = import.meta.env.VITE_HEAD
|
||||||
const assessors = JSON.parse(sessionStorage.getItem('registered')!)
|
const assessors = JSON.parse(sessionStorage.getItem('assessors')!)
|
||||||
const roles = ['Assessor', 'Approver']
|
const roles = ['Assessor', 'Approver']
|
||||||
|
|
||||||
const [role, setRole] = createSignal('Assessor')
|
const [role, setRole] = createSignal('')
|
||||||
const [name, setName] = createSignal('')
|
const [name, setName] = createSignal('')
|
||||||
const [password, setPassword] = createSignal('')
|
const [password, setPassword] = createSignal('')
|
||||||
|
const [matched, setMatched] = createSignal(false)
|
||||||
|
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
|
|
||||||
|
|
@ -23,8 +24,13 @@ export default () => {
|
||||||
const dbpassword = await ofetch(API + 'get-password/' + employeeid.result, { parseResponse: JSON.parse })
|
const dbpassword = await ofetch(API + 'get-password/' + employeeid.result, { parseResponse: JSON.parse })
|
||||||
const hashPassword = await securePassword()
|
const hashPassword = await securePassword()
|
||||||
|
|
||||||
|
console.log('dbpassword', dbpassword.result)
|
||||||
|
console.log('hashPassword', hashPassword)
|
||||||
|
console.log(dbpassword.result === hashPassword)
|
||||||
|
|
||||||
if (dbpassword.result === hashPassword) {
|
if (dbpassword.result === hashPassword) {
|
||||||
navigate('/notification')
|
setMatched(true)
|
||||||
|
navigate('/')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -36,11 +42,6 @@ export default () => {
|
||||||
return thirdHashing.toString()
|
return thirdHashing.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
createEffect(() => {
|
|
||||||
if (role() === 'Approver') setName(APPROVERNAME)
|
|
||||||
else if (role() !== 'Approver' && name() === APPROVERNAME) setName('')
|
|
||||||
})
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Page alignment="column">
|
<Page alignment="column">
|
||||||
|
|
@ -64,14 +65,7 @@ export default () => {
|
||||||
<Row>
|
<Row>
|
||||||
<Box curved thickness={2} padding={2} color="#2f465cd7" background="#04040642">
|
<Box curved thickness={2} padding={2} color="#2f465cd7" background="#04040642">
|
||||||
<Row>
|
<Row>
|
||||||
<span
|
<span class="box-title">Login</span>
|
||||||
class="box-title"
|
|
||||||
onClick={() => {
|
|
||||||
console.log(name())
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Login
|
|
||||||
</span>
|
|
||||||
</Row>
|
</Row>
|
||||||
|
|
||||||
<Padding top={2} left={2} right={2} bottom={0}>
|
<Padding top={2} left={2} right={2} bottom={0}>
|
||||||
|
|
@ -90,28 +84,18 @@ export default () => {
|
||||||
<Input value={password()} onChange={setPassword}></Input>
|
<Input value={password()} onChange={setPassword}></Input>
|
||||||
|
|
||||||
<Padding top={2} left={0} right={0} bottom={0}>
|
<Padding top={2} left={0} right={0} bottom={0}>
|
||||||
<Show when={password() && name()}>
|
<Row>
|
||||||
<Row>
|
<Button edges="curved" design="bo-primary" label="Login" wide onClick={login}></Button>
|
||||||
<Button edges="curved" design="bo-primary" label="Login" wide onClick={login}></Button>
|
</Row>
|
||||||
</Row>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={!password() && name()}>
|
|
||||||
<Row>
|
|
||||||
<span class="required">Required password</span>
|
|
||||||
</Row>
|
|
||||||
</Show>
|
|
||||||
|
|
||||||
<Show when={!password() && !name()}>
|
|
||||||
<Row>
|
|
||||||
<span class="required">Required name and password</span>
|
|
||||||
</Row>
|
|
||||||
</Show>
|
|
||||||
</Padding>
|
</Padding>
|
||||||
</Box>
|
</Box>
|
||||||
</Row>
|
</Row>
|
||||||
</Padding>
|
</Padding>
|
||||||
</Page>
|
</Page>
|
||||||
|
|
||||||
|
<Modal trigger={matched()} background="#ffffffff" color="#000000e4" opacity={0.5}>
|
||||||
|
<h1>1</h1>
|
||||||
|
</Modal>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { ofetch } from 'ofetch'
|
||||||
import { SHA3, SHA1 } from 'crypto-js'
|
import { SHA3, SHA1 } from 'crypto-js'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { FileField } from '@kobalte/core/file-field'
|
import { FileField } from '@kobalte/core/file-field'
|
||||||
|
import bcrypt from 'bcryptjs'
|
||||||
|
|
||||||
export default () => {
|
export default () => {
|
||||||
const API = import.meta.env.VITE_BACKEND
|
const API = import.meta.env.VITE_BACKEND
|
||||||
|
|
@ -70,6 +71,8 @@ export default () => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const securePassword = async () => {
|
const securePassword = async () => {
|
||||||
|
// const salt = bcrypt.genSaltSync(9)
|
||||||
|
// const hash = bcrypt.hashSync(password(), salt)
|
||||||
const firstHashing = SHA1(password())
|
const firstHashing = SHA1(password())
|
||||||
const secondHashing = SHA3(firstHashing)
|
const secondHashing = SHA3(firstHashing)
|
||||||
const thirdHashing = SHA1(secondHashing)
|
const thirdHashing = SHA1(secondHashing)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue