first commit

This commit is contained in:
notnull 2019-07-13 16:03:04 -04:00
commit 521512e9a3
40 changed files with 14582 additions and 0 deletions

24
.gitignore vendored Normal file
View File

@ -0,0 +1,24 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
old

4
.prettierrc Normal file
View File

@ -0,0 +1,4 @@
trailingComma: "es5"
tabWidth: 2
semi: false
singleQuote: true

1
README.md Normal file
View File

@ -0,0 +1 @@
create-react-app nn-style

13487
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

41
package.json Normal file
View File

@ -0,0 +1,41 @@
{
"name": "blockchain-stories",
"version": "0.1.0",
"private": true,
"dependencies": {
"axios": "^0.19.0",
"bootstrap": "^4.3.1",
"concurrently": "^4.1.1",
"cors": "^2.8.5",
"express": "^4.17.1",
"morgan": "^1.9.1",
"pg": "^7.11.0",
"react": "^16.8.6",
"react-bootstrap": "^1.0.0-beta.9",
"react-datetime-picker": "^2.6.0",
"react-dom": "^16.8.6",
"react-scripts": "3.0.1",
"sequelize": "^5.10.0"
},
"scripts": {
"start": "concurrently --kill-others-on-fail \"node server\" \"react-scripts start\"",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

BIN
public/favicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

17
public/index.html Normal file
View File

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<title>app</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="app"></div>
</body>
</html>

15
public/manifest.json Normal file
View File

@ -0,0 +1,15 @@
{
"short_name": "app",
"name": "app",
"icons": [
{
"src": "favicon.png",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

35
server/api/blockchain.js Normal file
View File

@ -0,0 +1,35 @@
const router = require('express').Router()
const { Blockchain } = require('../db/models')
module.exports = router
router.get('/', async (req, res, next) => {
try {
const hashes = await Blockchain.findAll()
res.status(201).json(hashes)
} catch (err) {
next(err)
}
})
router.get('/:hash', async (req, res, next) => {
try {
const hash = await Blockchain.findOne({
where: { hashedStory: req.params.hashedStory },
})
res.status(201).json(hash)
} catch (err) {
next(err)
}
})
router.post('/', async (req, res, next) => {
try {
const hash = await Blockchain.create(req.body)
res.status(201).json(hash)
} catch (err) {
next(err)
}
})

11
server/api/index.js Executable file
View File

@ -0,0 +1,11 @@
const router = require('express').Router()
module.exports = router
router.use('/stories', require('./stories'))
router.use('/blockchain', require('./blockchain'))
router.use((req, res, next) => {
const error = new Error('Not Found!!!!!!!')
error.status = 404
next(error)
})

32
server/api/stories.js Executable file
View File

@ -0,0 +1,32 @@
const router = require('express').Router()
const { Story } = require('../db/models')
module.exports = router
router.post('/', async (req, res, next) => {
try {
const story = await Story.create(req.body)
res.json(story)
} catch (err) {
next(err)
}
})
router.post('/read', async (req, res, next) => {
try {
const story = await Story.find({
where: {
hash: req.body.hash,
},
})
if (story) {
res.json(story)
} else {
console.log('no story found.')
res.status(204).send()
}
} catch (err) {
next(err)
}
})

18
server/db/db.js Executable file
View File

@ -0,0 +1,18 @@
const Sequelize = require('sequelize')
const pkg = require('../../package.json')
const databaseName = pkg.name
const createDB = () => {
const db = new Sequelize(
process.env.DATABASE_URL || `postgres://localhost:5432/${databaseName}`,
{
logging: false,
}
)
return db
}
const db = createDB()
module.exports = db

6
server/db/index.js Executable file
View File

@ -0,0 +1,6 @@
const db = require("./db")
// register models
require("./models")
module.exports = db

View File

@ -0,0 +1,10 @@
const Sequelize = require('sequelize')
const db = require('../db')
const Blockchain = db.define('blockchain', {
hashedStory: {
type: Sequelize.STRING,
},
})
module.exports = Blockchain

4
server/db/models/index.js Executable file
View File

@ -0,0 +1,4 @@
const Story = require('./story')
const Blockchain = require('./blockchain')
module.exports = { Story, Blockchain }

16
server/db/models/story.js Executable file
View File

@ -0,0 +1,16 @@
const Sequelize = require('sequelize')
const db = require('../db')
const Story = db.define('story', {
dateOfEvent: {
type: Sequelize.STRING,
},
hashedStory: {
type: Sequelize.TEXT,
},
encryptedStory: {
type: Sequelize.TEXT,
},
})
module.exports = Story

28
server/db/seed.js Executable file
View File

@ -0,0 +1,28 @@
const db = require('../db')
const { Story, Blockchain } = require('./models')
const h1 = {
hashedStory: 'sasdvasd',
}
const s1 = { hashedStory: 'sasdvasd', encryptedStory: 'sdsdf' }
async function runSeed() {
await db.sync({ force: true })
console.log('db synced!')
console.log('seeding...')
try {
await Blockchain.create(h1)
await Story.create(s1)
console.log(`seeded successfully`)
} catch (err) {
console.error(err)
process.exitCode = 1
} finally {
console.log('closing db connection')
await db.close()
console.log('db connection closed')
}
}
runSeed()

26
server/index.js Executable file
View File

@ -0,0 +1,26 @@
const express = require('express')
const path = require('path')
const app = express()
const morgan = require('morgan')
const port = process.env.PORT || 1337
const cors = require('cors')
app.use(morgan('tiny'))
app.use(cors())
// body parsing middleware
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(require('body-parser').text())
app.use('/api', require('./api'))
app.get('*', (req, res) =>
res.sendFile(path.resolve(__dirname, '..', 'public', 'index.html'))
)
app.use((err, req, res, next) => {
console.error(err)
console.error(err.stack)
res.status(err.status || 500).send(err.message || 'Internal server error.')
})
app.listen(port, () => console.log(`Doin' haxor stuff on port ${port}`))

144
src/App.js Normal file
View File

@ -0,0 +1,144 @@
import React from 'react'
import {
Navbar,
Footer,
Home,
CreateStory,
RetrieveStory,
HashedStories,
} from './components'
import { Container } from 'react-bootstrap'
import axios from 'axios'
import {
encryptString,
decryptString,
generatePassword,
createHash,
} from './encrypt'
const initialState = {
loading: true,
component: 'home',
hashedStories: [],
encryptedStories: [],
}
const API = 'http://localhost:1337'
class App extends React.Component {
constructor() {
super()
this.state = initialState
this.navigate = this.navigate.bind(this)
this.submitStory = this.submitStory.bind(this)
}
componentWillMount() {
this.fetchData()
}
async fetchBlockchain() {
const { data } = await axios.get(API + '/api/blockchain')
return data
}
async fetchData() {
try {
const hashedStories = await this.fetchBlockchain()
this.setState({ hashedStories })
} catch (e) {
this.setState({ error: e.message })
} finally {
this.setState({ loading: false })
}
}
async submitStory(storyData) {
const { eventDetails } = storyData
const encryptionKey = generatePassword()
const encryptedStory = encryptString(eventDetails, encryptionKey)
const hashedStory = createHash(encryptedStory)
try {
await axios.post(API + '/api/stories', {
hashedStory,
encryptedStory,
})
await axios.post(API + '/api/blockchain', {
hashedStory,
})
this.setState({
encryptionKey,
hashedStory,
})
} catch (e) {
this.setState({ error: e.message })
}
}
async fetchStory(encryptionKey, hash) {
try {
const retrievedStory = await axios.get(`/api/stories/${hash}`)
const decryptedStory = decryptString(
retrievedStory.encryptedStory,
encryptionKey
)
return this.setState({ decryptedStory })
} catch (e) {
return this.setState({ retrievalError: 'Story not found' })
}
}
navigate(component) {
this.setState({ component })
}
renderLoading() {
return <div>loading...</div>
}
renderError() {
return <div>something went wrong.</div>
}
renderMain() {
if (this.state.component === 'home') return <Home {...this.state} />
if (this.state.component === 'create')
return (
<CreateStory
navigate={this.navigate}
submitStory={this.submitStory}
{...this.state}
/>
)
if (this.state.component === 'read')
return (
<RetrieveStory
navigate={this.navigate}
fetchStory={this.fetchStory}
{...this.state}
/>
)
if (this.state.component === 'hashed')
return <HashedStories navigate={this.navigate} {...this.state} />
return <div>something else happened.</div>
}
renderApp() {
return (
<Container>
<Navbar navigate={this.navigate} />
{this.renderMain()}
<Footer />
</Container>
)
}
render() {
if (this.state.loading) return this.renderLoading()
if (this.state.error) return this.renderError()
return this.renderApp()
}
}
export default App

View File

@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
it('renders without crashing', () => {
const div = document.createElement('div')
ReactDOM.render(<App />, div)
ReactDOM.unmountComponentAtNode(div)
})

View File

@ -0,0 +1,72 @@
import React from 'react'
import DateTimePicker from 'react-datetime-picker'
//----------------------------------------------//
const initialState = {
dateOfEvent: new Date(),
eventDetails: '',
}
class StoryForm extends React.Component {
constructor() {
super()
this.state = initialState
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
console.log(this.state)
this.setState({ [e.target.name]: e.target.value })
}
async handleSubmit(e) {
e.preventDefault()
this.props.submitStory({ ...this.state })
}
render() {
const { eventDetails } = this.props
return (
<div className="mt-5 mb-5">
{this.state.error ? <div>something went wrong.</div> : <div />}
<form onSubmit={this.handleSubmit}>
<div className="form-group">
<label htmlFor="dateOfEvent" className="col-form-label">
Date of Event
</label>
<DateTimePicker
className="mb-4 form-control"
id="dateOfEvent"
name="dateOfEvent"
/>
<div className="form-group">
<label htmlFor="eventDetails" className="col-form-label">
Event Details
</label>
<textarea
className="form-control"
type="text"
rows="5"
id="eventDetails"
name="eventDetails"
onChange={this.handleChange}
value={eventDetails}
/>
</div>
<button type="submit">Submit</button>
</div>
</form>
</div>
)
}
}
//----------------------------------------------//
export default StoryForm

View File

@ -0,0 +1,48 @@
import React from 'react'
//----------------------------------------------//
const StorySubmittedView = props => {
const { encryptionKey, hashedStory } = props
return (
<form>
<div className="form-group row">
<label htmlFor="password" className="col-sm-3 col-form-label">
Encryption Key:
</label>
<div className="col-sm-7">
<input
type="text"
readOnly
className="form-control-plaintext"
id="encryptionKey"
value={encryptionKey}
/>
</div>
</div>
<div className="form-group row">
<label htmlFor="hash" className="col-sm-3 col-form-label">
Hash:
</label>
<div className="col-sm-7">
<input
type="text"
readOnly
className="form-control-plaintext"
id="hash"
value={hashedStory}
/>
</div>
</div>
<div className="form-group row">
<div className="col">
Don't lose these or your data will be unable to be decrypted.
</div>
</div>
</form>
)
}
//----------------------------------------------//
export default StorySubmittedView

View File

@ -0,0 +1,10 @@
import React from 'react'
import CreateStoryForm from './CreateStoryForm'
import StorySubmittedView from './StorySubmittedView'
const ReadStory = props => {
if (props.hashedStory) return <StorySubmittedView {...props} />
return <CreateStoryForm {...props} />
}
export default ReadStory

11
src/components/Footer.js Normal file
View File

@ -0,0 +1,11 @@
import React from 'react'
const Footer = () => {
return (
<div className="footer bg-dark">
<p className="text-center text-white">Copyright &copy; 2018</p>
</div>
)
}
export default Footer

View File

@ -0,0 +1,25 @@
import React from 'react'
import { Table } from 'react-bootstrap'
const HashedStories = props => {
return (
<Table>
<thead>
<tr>
<th>ID</th>
<th>Story Hash</th>
</tr>
</thead>
<tbody>
{props.hashedStories.map(hs => (
<tr key={hs.id}>
<td>{hs.id}</td>
<td>{hs.hashedStory}</td>
</tr>
))}
</tbody>
</Table>
)
}
export default HashedStories

21
src/components/Home.js Normal file
View File

@ -0,0 +1,21 @@
import React from 'react'
const Home = props => {
return (
<div>
<h3>Welcome to Stories. </h3>
<p>
To submit a story on the "Add" page, enter your name and details. All of
your data will be encrypted before being sent to the server using an
automatically-generated password, which will be given to you, along with
the SHA256 hash value of the encrypted story.
</p>
<p>
When you're ready to retrieve your story, you will need the password and
the hash value. Without these, the data are unable to be retrieved.
</p>
</div>
)
}
export default Home

49
src/components/Navbar.js Normal file
View File

@ -0,0 +1,49 @@
import React from 'react'
import { Navbar, Nav } from 'react-bootstrap'
const AppNavbar = props => {
return (
<Navbar variant="dark" bg="dark" expand="lg">
<Navbar.Brand href="#home">Stories</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav className="mr-auto">
<Nav.Link
href="#home"
onClick={() => {
props.navigate('home')
}}
>
Home
</Nav.Link>
<Nav.Link
href="#create"
onClick={() => {
props.navigate('create')
}}
>
Create Story
</Nav.Link>
<Nav.Link
href="#read"
onClick={() => {
props.navigate('read')
}}
>
Retrieve Story
</Nav.Link>
<Nav.Link
href="#hashed"
onClick={() => {
props.navigate('hashed')
}}
>
See Hashes
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Navbar>
)
}
export default AppNavbar

View File

@ -0,0 +1,12 @@
import React from 'react'
const ReadStoryView = props => {
return (
<div>
<h3> {props.eventDate}</h3>
<p>{props.eventDetails}</p>
</div>
)
}
export default ReadStoryView

View File

@ -0,0 +1,87 @@
import React from 'react'
//----------------------------------------------//
const initialState = {
password: '',
hash: '',
}
class RetrieveStoryForm extends React.Component {
constructor() {
super()
this.state = initialState
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({ [e.target.name]: e.target.value })
}
handleSubmit(e) {
e.preventDefault()
try {
const encryptedStory = this.props.fetchStory(
this.state.password,
this.state.hash
)
this.props.navigate('read')
} catch (e) {
console.log(e)
}
}
render() {
return (
<div className="mt-3 mb-5">
<h3> Retrieve A Story</h3>
<p>Enter your secret key and your hash below.</p>
<form onSubmit={this.handleSubmit}>
<div className="form-group row">
<label htmlFor="password" className="col-sm-3 col-form-label">
Password
</label>
<div className="col-sm-7">
<input
type="text"
className="form-control"
id="password"
name="password"
placeholder="Password"
onChange={this.handleChange}
value={this.state.password}
/>
</div>
</div>
<div className="form-group row">
<label htmlFor="hash" className="col-sm-3 col-form-label">
Hash:
</label>
<div className="col-sm-7">
<input
type="text"
className="form-control"
id="hash"
name="hash"
placeholder="Hash"
onChange={this.handleChange}
value={this.state.hash}
/>
</div>
</div>
<div className="form-group row">
<div className="col-sm-3">
<button className="btn btn-dark " type="submit">
Submit
</button>
</div>
</div>
</form>
</div>
)
}
}
//----------------------------------------------//
export default RetrieveStoryForm

View File

@ -0,0 +1,10 @@
import React from 'react'
import ReadStoryView from './ReadStoryView'
import RetrieveStoryForm from './RetrieveStoryForm'
const ReadStory = props => {
if (props.retrievedStory) return <ReadStoryView {...props} />
return <RetrieveStoryForm {...props} />
}
export default ReadStory

7
src/components/index.js Normal file
View File

@ -0,0 +1,7 @@
export { default as Navbar } from './Navbar'
export { default as Footer } from './Footer'
export { default as Home } from './Home'
export { default as CreateStory } from './CreateStory'
export { default as HashedStories } from './HashedStories'
export { default as RetrieveStory } from './RetrieveStory'

View File

@ -0,0 +1,7 @@
const crypto = require('crypto')
export default plainText =>
crypto
.createHash('sha256')
.update(plainText)
.digest('base64')

View File

@ -0,0 +1,51 @@
const ALGORITHM_NAME = 'aes-128-gcm'
const ALGORITHM_NONCE_SIZE = 12
const ALGORITHM_TAG_SIZE = 16
const ALGORITHM_KEY_SIZE = 16
const PBKDF2_NAME = 'sha256'
const PBKDF2_SALT_SIZE = 16
const PBKDF2_ITERATIONS = 32767
export default function decryptString(
base64CiphertextAndNonceAndSalt,
password
) {
// Decode the base64.
let ciphertextAndNonceAndSalt = new Buffer(
base64CiphertextAndNonceAndSalt,
'base64'
)
// Create buffers of salt and ciphertextAndNonce.
let salt = ciphertextAndNonceAndSalt.slice(0, PBKDF2_SALT_SIZE)
let ciphertextAndNonce = ciphertextAndNonceAndSalt.slice(PBKDF2_SALT_SIZE)
// Derive the key using PBKDF2.
let key = crypto.pbkdf2Sync(
new Buffer(password, 'utf8'),
salt,
PBKDF2_ITERATIONS,
ALGORITHM_KEY_SIZE,
PBKDF2_NAME
)
// Decrypt and return result.
return decrypt(ciphertextAndNonce, key).toString('utf8')
}
function decrypt(ciphertextAndNonce, key) {
// Create buffers of nonce, ciphertext and tag.
let nonce = ciphertextAndNonce.slice(0, ALGORITHM_NONCE_SIZE)
let ciphertext = ciphertextAndNonce.slice(
ALGORITHM_NONCE_SIZE,
ciphertextAndNonce.length - ALGORITHM_TAG_SIZE
)
let tag = ciphertextAndNonce.slice(ciphertext.length + ALGORITHM_NONCE_SIZE)
// Create the cipher instance.
let cipher = crypto.createDecipheriv(ALGORITHM_NAME, key, nonce)
// Decrypt and return result.
cipher.setAuthTag(tag)
return Buffer.concat([cipher.update(ciphertext), cipher.final()])
}

View File

@ -0,0 +1,44 @@
const crypto = require('crypto')
const ALGORITHM_NAME = 'aes-128-gcm'
const ALGORITHM_NONCE_SIZE = 12
const ALGORITHM_KEY_SIZE = 16
const PBKDF2_NAME = 'sha256'
const PBKDF2_SALT_SIZE = 16
const PBKDF2_ITERATIONS = 32767
export default function encryptString(plaintext, password) {
// Generate a 128-bit salt using a CSPRNG.
let salt = crypto.randomBytes(PBKDF2_SALT_SIZE)
// Derive a key using PBKDF2.
let key = crypto.pbkdf2Sync(
new Buffer(password, 'utf8'),
salt,
PBKDF2_ITERATIONS,
ALGORITHM_KEY_SIZE,
PBKDF2_NAME
)
// Encrypt and prepend salt.
let ciphertextAndNonceAndSalt = Buffer.concat([
salt,
encrypt(new Buffer(plaintext, 'utf8'), key),
])
// Return as base64 string.
return ciphertextAndNonceAndSalt.toString('base64')
}
function encrypt(plaintext, key) {
// Generate a 96-bit nonce using a CSPRNG.
let nonce = crypto.randomBytes(ALGORITHM_NONCE_SIZE)
// Create the cipher instance.
let cipher = crypto.createCipheriv(ALGORITHM_NAME, key, nonce)
// Encrypt and prepend nonce.
let ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()])
return Buffer.concat([nonce, ciphertext, cipher.getAuthTag()])
}

View File

@ -0,0 +1,15 @@
const MIN = 10
const MAX = 20
const ALL_CHARS =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(){}:,.<>?'
const generatePassword = () => {
let key = ''
const passwordLength = Math.floor(Math.random() * (MAX - MIN + 1) + MIN)
for (let i = 0; i < passwordLength; i++) {
key += ALL_CHARS.charAt(Math.floor(Math.random() * ALL_CHARS.length))
}
return key
}
export default generatePassword

View File

@ -0,0 +1,5 @@
function generateSalt() {
// Generate a 128-bit salt using a CSPRNG.
return crypto.randomBytes(PBKDF2_SALT_SIZE)
}
export default generateSalt

30
src/encrypt/hash-story.js Normal file
View File

@ -0,0 +1,30 @@
const story = {
dateOfEvent: '12345',
eventDetails: `Finding duplicate records
Main article: Hash table
When storing records in a large unsorted file, one may use a hash function to map each record to an index into a table T, and to collect in each bucket T[i] a list of the numbers of all records with the same hash value i. Once the table is complete, any two duplicate records will end up in the same bucket. The duplicates can then be found by scanning every bucket T[i] which contains two or more members, fetching those records, and comparing them. With a table of appropriate size, this method is likely to be much faster than any alternative approach (such as sorting the file and comparing all consecutive pairs).
Protecting data
Main article: Security of cryptographic hash functions
A hash value can be used to uniquely identify secret information. This requires that the hash function is collision-resistant, which means that it is very hard to find data that will generate the same hash value. These functions are categorized into cryptographic hash functions and provably secure hash functions. Functions in the second category are the most secure but also too slow for most practical purposes. Collision resistance is accomplished in part by generating very large hash values. For example, SHA-2, one of the most widely used cryptographic hash functions, generates 256-bit values.
Finding similar records
Main article: Locality sensitive hashing
Hash functions can also be used to locate table records whose key is similar, but not identical, to a given key; or pairs of records in a large file which have similar keys. For that purpose, one needs a hash function that maps similar keys to hash values that differ by at most m, where m is a small integer (say, 1 or 2). If one builds a table T of all record numbers, using such a hash function, then similar records will end up in the same bucket, or in nearby buckets. Then one need only check the records in each bucket T[i] against those in buckets T[i+k] where k ranges between m and m.
This class includes the so-called acoustic fingerprint algorithms, that are used to locate similar-sounding entries in large collection of audio files. For this application, the hash function must be as insensitive as possible to data capture or transmission errors, and to trivial changes such as timing and volume changes, compression, etc.[3]
Finding similar substrings
The same techniques can be used to find equal or similar stretches in a large collection of strings, such as a document repository or a genomic database. In this case, the input strings are broken into many small pieces, and a hash function is used to detect potentially equal pieces, as above.
The RabinKarp algorithm is a relatively fast string searching algorithm that works in O(n) time on average. It is based on the use of hashing to compare strings.
Geometric hashing
This principle is widely used in computer graphics, computational geometry and many other disciplines, to solve many proximity problems in the plane or in three-dimensional space, such as finding closest pairs in a set of points, similar shapes in a list of shapes, similar images in an image database, and so on. In these applications, the set of all inputs is some sort of metric space, and the hashing function can be interpreted as a partition of that space into a grid of cells. The table is often an array with two or more indices (called a grid file, grid index, bucket grid, and similar names), and the hash function returns an index tuple. This special case of hashing is known as geometric hashing or the grid method. Geometric hashing is also used in telecommunications (usually under the name vector quantization) to encode and compress multi-dimensional signals.
Standard uses of hashing in cryptography
Main article: Cryptographic hash function
Some standard applications that employ hash functions include authentication, message integrity (using an HMAC (Hashed MAC)), message fingerprinting, data corruption detection, and digital signature efficiency.
`,
}
export default story

5
src/encrypt/index.js Normal file
View File

@ -0,0 +1,5 @@
export { default as encryptString } from './encryptString'
export { default as decryptString } from './decryptString'
export { default as generatePassword } from './generatePassword'
export { default as createHash } from './createHash'
export { default as testStory } from './hash-story'

10
src/index.js Normal file
View File

@ -0,0 +1,10 @@
import React from 'react'
import ReactDOM from 'react-dom'
import 'bootstrap/dist/css/bootstrap.css'
import App from './App'
import * as serviceWorker from './serviceWorker'
ReactDOM.render(<App />, document.getElementById('app'))
serviceWorker.unregister()

135
src/serviceWorker.js Normal file
View File

@ -0,0 +1,135 @@
// This optional code is used to register a service worker.
// register() is not called by default.
// This lets the app load faster on subsequent visits in production, and gives
// it offline capabilities. However, it also means that developers (and users)
// will only see deployed updates on subsequent visits to a page, after all the
// existing tabs open on the page have been closed, since previously cached
// resources are updated in the background.
// To learn more about the benefits of this model and instructions on how to
// opt-in, read https://bit.ly/CRA-PWA
const isLocalhost = Boolean(
window.location.hostname === 'localhost' ||
// [::1] is the IPv6 localhost address.
window.location.hostname === '[::1]' ||
// 127.0.0.1/8 is considered localhost for IPv4.
window.location.hostname.match(
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
)
);
export function register(config) {
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
// The URL constructor is available in all browsers that support SW.
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
if (publicUrl.origin !== window.location.origin) {
// Our service worker won't work if PUBLIC_URL is on a different origin
// from what our page is served on. This might happen if a CDN is used to
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
return;
}
window.addEventListener('load', () => {
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
if (isLocalhost) {
// This is running on localhost. Let's check if a service worker still exists or not.
checkValidServiceWorker(swUrl, config);
// Add some additional logging to localhost, pointing developers to the
// service worker/PWA documentation.
navigator.serviceWorker.ready.then(() => {
console.log(
'This web app is being served cache-first by a service ' +
'worker. To learn more, visit https://bit.ly/CRA-PWA'
);
});
} else {
// Is not localhost. Just register service worker
registerValidSW(swUrl, config);
}
});
}
}
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}
function checkValidServiceWorker(swUrl, config) {
// Check if the service worker can be found. If it can't reload the page.
fetch(swUrl)
.then(response => {
// Ensure service worker exists, and that we really are getting a JS file.
const contentType = response.headers.get('content-type');
if (
response.status === 404 ||
(contentType != null && contentType.indexOf('javascript') === -1)
) {
// No service worker found. Probably a different app. Reload the page.
navigator.serviceWorker.ready.then(registration => {
registration.unregister().then(() => {
window.location.reload();
});
});
} else {
// Service worker found. Proceed as normal.
registerValidSW(swUrl, config);
}
})
.catch(() => {
console.log(
'No internet connection found. App is running in offline mode.'
);
});
}
export function unregister() {
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(registration => {
registration.unregister();
});
}
}