Compare commits
5 Commits
master
...
production
Author | SHA1 | Date |
---|---|---|
|
32df3370e2 | 8 years ago |
|
d81195856a | 8 years ago |
|
6ed427658e | 8 years ago |
|
08eddc7e80 | 8 years ago |
|
d040dedc6e | 8 years ago |
36 changed files with 178 additions and 2727 deletions
@ -1,8 +0,0 @@ |
||||
Dockerfile |
||||
.git |
||||
npm-debug.log |
||||
node_modules |
||||
*.swp |
||||
*.swo |
||||
data |
||||
*.DS_Store |
@ -1,2 +0,0 @@ |
||||
**/*.min.js |
||||
config.js |
@ -1,25 +0,0 @@ |
||||
{ |
||||
"env": { |
||||
"es6": true, |
||||
"node": true |
||||
}, |
||||
"extends": "eslint:recommended", |
||||
"rules": { |
||||
"indent": [ |
||||
"error", |
||||
2 |
||||
], |
||||
"linebreak-style": [ |
||||
"error", |
||||
"unix" |
||||
], |
||||
"quotes": [ |
||||
"error", |
||||
"single" |
||||
], |
||||
"semi": [ |
||||
"error", |
||||
"always" |
||||
] |
||||
} |
||||
} |
@ -1 +0,0 @@ |
||||
* @toptal/site-acquisition-eng |
@ -1,30 +0,0 @@ |
||||
name: Close inactive issues and PRs |
||||
on: |
||||
workflow_dispatch: |
||||
schedule: |
||||
- cron: "30 1 * * *" |
||||
|
||||
jobs: |
||||
close-stale: |
||||
runs-on: ubuntu-latest |
||||
permissions: |
||||
issues: write |
||||
pull-requests: write |
||||
steps: |
||||
- uses: actions/stale@v3 |
||||
with: |
||||
days-before-stale: 30 |
||||
days-before-close: 14 |
||||
stale-issue-label: "stale" |
||||
stale-pr-label: "stale" |
||||
|
||||
exempt-issue-labels: backlog,triage,nostale |
||||
exempt-pr-labels: backlog,triage,nostale |
||||
|
||||
stale-pr-message: "This PR is stale because it has been open for 30 days with no activity." |
||||
close-pr-message: "This PR was closed because it has been inactive for 14 days since being marked as stale." |
||||
|
||||
stale-issue-message: "This issue is stale because it has been open for 30 days with no activity." |
||||
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." |
||||
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }} |
@ -1,68 +0,0 @@ |
||||
FROM node:14.8.0-stretch |
||||
|
||||
RUN mkdir -p /usr/src/app && \ |
||||
chown node:node /usr/src/app |
||||
|
||||
USER node:node |
||||
|
||||
WORKDIR /usr/src/app |
||||
|
||||
COPY --chown=node:node . . |
||||
|
||||
RUN npm install && \ |
||||
npm install redis@0.8.1 && \ |
||||
npm install pg@4.1.1 && \ |
||||
npm install memcached@2.2.2 && \ |
||||
npm install aws-sdk@2.738.0 && \ |
||||
npm install rethinkdbdash@2.3.31 |
||||
|
||||
ENV STORAGE_TYPE=memcached \ |
||||
STORAGE_HOST=127.0.0.1 \ |
||||
STORAGE_PORT=11211\ |
||||
STORAGE_EXPIRE_SECONDS=2592000\ |
||||
STORAGE_DB=2 \ |
||||
STORAGE_AWS_BUCKET= \ |
||||
STORAGE_AWS_REGION= \ |
||||
STORAGE_USENAME= \ |
||||
STORAGE_PASSWORD= \ |
||||
STORAGE_FILEPATH= |
||||
|
||||
ENV LOGGING_LEVEL=verbose \ |
||||
LOGGING_TYPE=Console \ |
||||
LOGGING_COLORIZE=true |
||||
|
||||
ENV HOST=0.0.0.0\ |
||||
PORT=7777\ |
||||
KEY_LENGTH=10\ |
||||
MAX_LENGTH=400000\ |
||||
STATIC_MAX_AGE=86400\ |
||||
RECOMPRESS_STATIC_ASSETS=true |
||||
|
||||
ENV KEYGENERATOR_TYPE=phonetic \ |
||||
KEYGENERATOR_KEYSPACE= |
||||
|
||||
ENV RATELIMITS_NORMAL_TOTAL_REQUESTS=500\ |
||||
RATELIMITS_NORMAL_EVERY_MILLISECONDS=60000 \ |
||||
RATELIMITS_WHITELIST_TOTAL_REQUESTS= \ |
||||
RATELIMITS_WHITELIST_EVERY_MILLISECONDS= \ |
||||
# comma separated list for the whitelisted \ |
||||
RATELIMITS_WHITELIST=example1.whitelist,example2.whitelist \ |
||||
\ |
||||
RATELIMITS_BLACKLIST_TOTAL_REQUESTS= \ |
||||
RATELIMITS_BLACKLIST_EVERY_MILLISECONDS= \ |
||||
# comma separated list for the blacklisted \ |
||||
RATELIMITS_BLACKLIST=example1.blacklist,example2.blacklist |
||||
ENV DOCUMENTS=about=./about.md |
||||
|
||||
EXPOSE ${PORT} |
||||
STOPSIGNAL SIGINT |
||||
ENTRYPOINT [ "bash", "docker-entrypoint.sh" ] |
||||
|
||||
HEALTHCHECK --interval=30s --timeout=30s --start-period=5s \ |
||||
--retries=3 CMD [ "sh", "-c", "echo -n 'curl localhost:7777... '; \ |
||||
(\ |
||||
curl -sf localhost:7777 > /dev/null\ |
||||
) && echo OK || (\ |
||||
echo Fail && exit 2\ |
||||
)"] |
||||
CMD ["npm", "start"] |
@ -1,12 +0,0 @@ |
||||
version: '3.0' |
||||
services: |
||||
haste-server: |
||||
build: . |
||||
environment: |
||||
- STORAGE_TYPE=memcached |
||||
- STORAGE_HOST=memcached |
||||
- STORAGE_PORT=11211 |
||||
ports: |
||||
- 7777:7777 |
||||
memcached: |
||||
image: memcached:latest |
@ -1,108 +0,0 @@ |
||||
const { |
||||
HOST, |
||||
PORT, |
||||
KEY_LENGTH, |
||||
MAX_LENGTH, |
||||
STATIC_MAX_AGE, |
||||
RECOMPRESS_STATIC_ASSETS, |
||||
STORAGE_TYPE, |
||||
STORAGE_HOST, |
||||
STORAGE_PORT, |
||||
STORAGE_EXPIRE_SECONDS, |
||||
STORAGE_DB, |
||||
STORAGE_AWS_BUCKET, |
||||
STORAGE_AWS_REGION, |
||||
STORAGE_PASSWORD, |
||||
STORAGE_USERNAME, |
||||
STORAGE_FILEPATH, |
||||
LOGGING_LEVEL, |
||||
LOGGING_TYPE, |
||||
LOGGING_COLORIZE, |
||||
KEYGENERATOR_TYPE, |
||||
KEY_GENERATOR_KEYSPACE, |
||||
RATE_LIMITS_NORMAL_TOTAL_REQUESTS, |
||||
RATE_LIMITS_NORMAL_EVERY_MILLISECONDS, |
||||
RATE_LIMITS_WHITELIST_TOTAL_REQUESTS, |
||||
RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS, |
||||
RATE_LIMITS_WHITELIST, |
||||
RATE_LIMITS_BLACKLIST_TOTAL_REQUESTS, |
||||
RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS, |
||||
RATE_LIMITS_BLACKLIST, |
||||
DOCUMENTS, |
||||
} = process.env; |
||||
|
||||
const config = { |
||||
host: HOST, |
||||
port: Number(PORT), |
||||
|
||||
keyLength: Number(KEY_LENGTH), |
||||
|
||||
maxLength: Number(MAX_LENGTH), |
||||
|
||||
staticMaxAge: Number(STATIC_MAX_AGE), |
||||
|
||||
recompressStaticAssets: RECOMPRESS_STATIC_ASSETS, |
||||
|
||||
logging: [ |
||||
{ |
||||
level: LOGGING_LEVEL, |
||||
type: LOGGING_TYPE, |
||||
colorize: LOGGING_COLORIZE, |
||||
}, |
||||
], |
||||
|
||||
keyGenerator: { |
||||
type: KEYGENERATOR_TYPE, |
||||
keyspace: KEY_GENERATOR_KEYSPACE, |
||||
}, |
||||
|
||||
rateLimits: { |
||||
whitelist: RATE_LIMITS_WHITELIST ? RATE_LIMITS_WHITELIST.split(",") : [], |
||||
blacklist: RATE_LIMITS_BLACKLIST ? RATE_LIMITS_BLACKLIST.split(",") : [], |
||||
categories: { |
||||
normal: { |
||||
totalRequests: RATE_LIMITS_NORMAL_TOTAL_REQUESTS, |
||||
every: RATE_LIMITS_NORMAL_EVERY_MILLISECONDS, |
||||
}, |
||||
whitelist: |
||||
RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS || |
||||
RATE_LIMITS_WHITELIST_TOTAL_REQUESTS |
||||
? { |
||||
totalRequests: RATE_LIMITS_WHITELIST_TOTAL_REQUESTS, |
||||
every: RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS, |
||||
} |
||||
: null, |
||||
blacklist: |
||||
RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS || |
||||
RATE_LIMITS_BLACKLIST_TOTAL_REQUESTS |
||||
? { |
||||
totalRequests: RATE_LIMITS_WHITELIST_TOTAL_REQUESTS, |
||||
every: RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS, |
||||
} |
||||
: null, |
||||
}, |
||||
}, |
||||
|
||||
storage: { |
||||
type: STORAGE_TYPE, |
||||
host: STORAGE_HOST, |
||||
port: Number(STORAGE_PORT), |
||||
expire: Number(STORAGE_EXPIRE_SECONDS), |
||||
bucket: STORAGE_AWS_BUCKET, |
||||
region: STORAGE_AWS_REGION, |
||||
connectionUrl: `postgres://${STORAGE_USERNAME}:${STORAGE_PASSWORD}@${STORAGE_HOST}:${STORAGE_PORT}/${STORAGE_DB}`, |
||||
db: STORAGE_DB, |
||||
user: STORAGE_USERNAME, |
||||
password: STORAGE_PASSWORD, |
||||
path: STORAGE_FILEPATH, |
||||
}, |
||||
|
||||
documents: DOCUMENTS |
||||
? DOCUMENTS.split(",").reduce((acc, item) => { |
||||
const keyAndValueArray = item.replace(/\s/g, "").split("="); |
||||
return { ...acc, [keyAndValueArray[0]]: keyAndValueArray[1] }; |
||||
}, {}) |
||||
: null, |
||||
}; |
||||
|
||||
console.log(JSON.stringify(config)); |
@ -1,9 +0,0 @@ |
||||
#!/bin/bash |
||||
|
||||
# We use this file to translate environmental variables to .env files used by the application |
||||
|
||||
set -e |
||||
|
||||
node ./docker-entrypoint.js > ./config.js |
||||
|
||||
exec "$@" |
@ -1,56 +0,0 @@ |
||||
/*global require,module,process*/ |
||||
|
||||
var AWS = require('aws-sdk'); |
||||
var winston = require('winston'); |
||||
|
||||
var AmazonS3DocumentStore = function(options) { |
||||
this.expire = options.expire; |
||||
this.bucket = options.bucket; |
||||
this.client = new AWS.S3({region: options.region}); |
||||
}; |
||||
|
||||
AmazonS3DocumentStore.prototype.get = function(key, callback, skipExpire) { |
||||
var _this = this; |
||||
|
||||
var req = { |
||||
Bucket: _this.bucket, |
||||
Key: key |
||||
}; |
||||
|
||||
_this.client.getObject(req, function(err, data) { |
||||
if(err) { |
||||
callback(false); |
||||
} |
||||
else { |
||||
callback(data.Body.toString('utf-8')); |
||||
if (_this.expire && !skipExpire) { |
||||
winston.warn('amazon s3 store cannot set expirations on keys'); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
AmazonS3DocumentStore.prototype.set = function(key, data, callback, skipExpire) { |
||||
var _this = this; |
||||
|
||||
var req = { |
||||
Bucket: _this.bucket, |
||||
Key: key, |
||||
Body: data, |
||||
ContentType: 'text/plain' |
||||
}; |
||||
|
||||
_this.client.putObject(req, function(err, data) { |
||||
if (err) { |
||||
callback(false); |
||||
} |
||||
else { |
||||
callback(true); |
||||
if (_this.expire && !skipExpire) { |
||||
winston.warn('amazon s3 store cannot set expirations on keys'); |
||||
} |
||||
} |
||||
}); |
||||
} |
||||
|
||||
module.exports = AmazonS3DocumentStore; |
@ -1,89 +0,0 @@ |
||||
/*global require,module,process*/ |
||||
|
||||
const Datastore = require('@google-cloud/datastore'); |
||||
const winston = require('winston'); |
||||
|
||||
class GoogleDatastoreDocumentStore { |
||||
|
||||
// Create a new store with options
|
||||
constructor(options) { |
||||
this.kind = "Haste"; |
||||
this.expire = options.expire; |
||||
this.datastore = new Datastore(); |
||||
} |
||||
|
||||
// Save file in a key
|
||||
set(key, data, callback, skipExpire) { |
||||
var expireTime = (skipExpire || this.expire === undefined) ? null : new Date(Date.now() + this.expire * 1000); |
||||
|
||||
var taskKey = this.datastore.key([this.kind, key]) |
||||
var task = { |
||||
key: taskKey, |
||||
data: [ |
||||
{ |
||||
name: 'value', |
||||
value: data, |
||||
excludeFromIndexes: true |
||||
}, |
||||
{ |
||||
name: 'expiration', |
||||
value: expireTime |
||||
} |
||||
] |
||||
}; |
||||
|
||||
this.datastore.insert(task).then(() => { |
||||
callback(true); |
||||
}) |
||||
.catch(err => { |
||||
callback(false); |
||||
}); |
||||
} |
||||
|
||||
// Get a file from a key
|
||||
get(key, callback, skipExpire) { |
||||
var taskKey = this.datastore.key([this.kind, key]) |
||||
|
||||
this.datastore.get(taskKey).then((entity) => { |
||||
if (skipExpire || entity[0]["expiration"] == null) { |
||||
callback(entity[0]["value"]); |
||||
} |
||||
else { |
||||
// check for expiry
|
||||
if (entity[0]["expiration"] < new Date()) { |
||||
winston.info("document expired", {key: key, expiration: entity[0]["expiration"], check: new Date(null)}); |
||||
callback(false); |
||||
} |
||||
else { |
||||
// update expiry
|
||||
var task = { |
||||
key: taskKey, |
||||
data: [ |
||||
{ |
||||
name: 'value', |
||||
value: entity[0]["value"], |
||||
excludeFromIndexes: true |
||||
}, |
||||
{ |
||||
name: 'expiration', |
||||
value: new Date(Date.now() + this.expire * 1000) |
||||
} |
||||
] |
||||
}; |
||||
this.datastore.update(task).then(() => { |
||||
}) |
||||
.catch(err => { |
||||
winston.error("failed to update expiration", {error: err}); |
||||
}); |
||||
callback(entity[0]["value"]); |
||||
} |
||||
} |
||||
}) |
||||
.catch(err => { |
||||
winston.error("Error retrieving value from Google Datastore", {error: err}); |
||||
callback(false); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
module.exports = GoogleDatastoreDocumentStore; |
@ -1,54 +1,45 @@ |
||||
const memcached = require('memcached'); |
||||
const winston = require('winston'); |
||||
|
||||
class MemcachedDocumentStore { |
||||
var memcached = require('memcache'); |
||||
var winston = require('winston'); |
||||
|
||||
// Create a new store with options
|
||||
constructor(options) { |
||||
var MemcachedDocumentStore = function(options) { |
||||
this.expire = options.expire; |
||||
|
||||
const host = options.host || '127.0.0.1'; |
||||
const port = options.port || 11211; |
||||
const url = `${host}:${port}`; |
||||
this.connect(url); |
||||
if (!MemcachedDocumentStore.client) { |
||||
MemcachedDocumentStore.connect(options); |
||||
} |
||||
}; |
||||
|
||||
// Create a connection
|
||||
connect(url) { |
||||
this.client = new memcached(url); |
||||
|
||||
winston.info(`connecting to memcached on ${url}`); |
||||
|
||||
this.client.on('failure', function(error) { |
||||
winston.info('error connecting to memcached', {error}); |
||||
MemcachedDocumentStore.connect = function(options) { |
||||
var host = options.host || '127.0.0.1'; |
||||
var port = options.port || 11211; |
||||
this.client = new memcached.Client(port, host); |
||||
this.client.connect(); |
||||
this.client.on('connect', function() { |
||||
winston.info('connected to memcached on ' + host + ':' + port); |
||||
}); |
||||
} |
||||
this.client.on('error', function(e) { |
||||
winston.info('error connecting to memcached', { error: e }); |
||||
}); |
||||
}; |
||||
|
||||
// Save file in a key
|
||||
set(key, data, callback, skipExpire) { |
||||
this.client.set(key, data, skipExpire ? 0 : this.expire || 0, (error) => { |
||||
callback(!error); |
||||
}); |
||||
} |
||||
MemcachedDocumentStore.prototype.set = |
||||
function(key, data, callback, skipExpire) { |
||||
MemcachedDocumentStore.client.set(key, data, function(err, reply) { |
||||
err ? callback(false) : callback(true); |
||||
}, skipExpire ? 0 : this.expire); |
||||
}; |
||||
|
||||
// Get a file from a key
|
||||
get(key, callback, skipExpire) { |
||||
this.client.get(key, (error, data) => { |
||||
const value = error ? false : data; |
||||
|
||||
callback(value); |
||||
|
||||
// Update the key so that the expiration is pushed forward
|
||||
if (value && !skipExpire) { |
||||
this.set(key, data, (updateSucceeded) => { |
||||
if (!updateSucceeded) { |
||||
winston.error('failed to update expiration on GET', {key}); |
||||
} |
||||
}, skipExpire); |
||||
MemcachedDocumentStore.prototype.get = function(key, callback, skipExpire) { |
||||
var _this = this; |
||||
MemcachedDocumentStore.client.get(key, function(err, reply) { |
||||
callback(err ? false : reply); |
||||
if (_this.expire && !skipExpire) { |
||||
winston.warn('store does not currently push forward expirations on GET'); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
} |
||||
}; |
||||
|
||||
module.exports = MemcachedDocumentStore; |
||||
|
@ -1,88 +0,0 @@ |
||||
|
||||
|
||||
var MongoClient = require('mongodb').MongoClient, |
||||
winston = require('winston'); |
||||
|
||||
var MongoDocumentStore = function (options) { |
||||
this.expire = options.expire; |
||||
this.connectionUrl = process.env.DATABASE_URl || options.connectionUrl; |
||||
}; |
||||
|
||||
MongoDocumentStore.prototype.set = function (key, data, callback, skipExpire) { |
||||
var now = Math.floor(new Date().getTime() / 1000), |
||||
that = this; |
||||
|
||||
this.safeConnect(function (err, db) { |
||||
if (err) |
||||
return callback(false); |
||||
|
||||
db.collection('entries').update({ |
||||
'entry_id': key, |
||||
$or: [ |
||||
{ expiration: -1 }, |
||||
{ expiration: { $gt: now } } |
||||
] |
||||
}, { |
||||
'entry_id': key, |
||||
'value': data, |
||||
'expiration': that.expire && !skipExpire ? that.expire + now : -1 |
||||
}, { |
||||
upsert: true |
||||
}, function (err, existing) { |
||||
if (err) { |
||||
winston.error('error persisting value to mongodb', { error: err }); |
||||
return callback(false); |
||||
} |
||||
|
||||
callback(true); |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
MongoDocumentStore.prototype.get = function (key, callback, skipExpire) { |
||||
var now = Math.floor(new Date().getTime() / 1000), |
||||
that = this; |
||||
|
||||
this.safeConnect(function (err, db) { |
||||
if (err) |
||||
return callback(false); |
||||
|
||||
db.collection('entries').findOne({ |
||||
'entry_id': key, |
||||
$or: [ |
||||
{ expiration: -1 }, |
||||
{ expiration: { $gt: now } } |
||||
] |
||||
}, function (err, entry) { |
||||
if (err) { |
||||
winston.error('error persisting value to mongodb', { error: err }); |
||||
return callback(false); |
||||
} |
||||
|
||||
callback(entry === null ? false : entry.value); |
||||
|
||||
if (entry !== null && entry.expiration !== -1 && that.expire && !skipExpire) { |
||||
db.collection('entries').update({ |
||||
'entry_id': key |
||||
}, { |
||||
$set: { |
||||
'expiration': that.expire + now |
||||
} |
||||
}, function (err, result) { }); |
||||
} |
||||
}); |
||||
}); |
||||
}; |
||||
|
||||
MongoDocumentStore.prototype.safeConnect = function (callback) { |
||||
MongoClient.connect(this.connectionUrl, function (err, db) { |
||||
if (err) { |
||||
winston.error('error connecting to mongodb', { error: err }); |
||||
callback(err); |
||||
} else { |
||||
callback(undefined, db); |
||||
} |
||||
}); |
||||
}; |
||||
|
||||
module.exports = MongoDocumentStore; |
@ -1,46 +0,0 @@ |
||||
const crypto = require('crypto'); |
||||
const rethink = require('rethinkdbdash'); |
||||
const winston = require('winston'); |
||||
|
||||
const md5 = (str) => { |
||||
const md5sum = crypto.createHash('md5'); |
||||
md5sum.update(str); |
||||
return md5sum.digest('hex'); |
||||
}; |
||||
|
||||
class RethinkDBStore { |
||||
constructor(options) { |
||||
this.client = rethink({ |
||||
silent: true, |
||||
host: options.host || '127.0.0.1', |
||||
port: options.port || 28015, |
||||
db: options.db || 'haste', |
||||
user: options.user || 'admin', |
||||
password: options.password || '' |
||||
}); |
||||
} |
||||
|
||||
set(key, data, callback) { |
||||
this.client.table('uploads').insert({ id: md5(key), data: data }).run((error) => { |
||||
if (error) { |
||||
callback(false); |
||||
winston.error('failed to insert to table', error); |
||||
return; |
||||
} |
||||
callback(true); |
||||
}); |
||||
} |
||||
|
||||
get(key, callback) { |
||||
this.client.table('uploads').get(md5(key)).run((error, result) => { |
||||
if (error || !result) { |
||||
callback(false); |
||||
if (error) winston.error('failed to insert to table', error); |
||||
return; |
||||
} |
||||
callback(result.data); |
||||
}); |
||||
} |
||||
} |
||||
|
||||
module.exports = RethinkDBStore; |
@ -1,32 +0,0 @@ |
||||
const fs = require('fs'); |
||||
|
||||
module.exports = class DictionaryGenerator { |
||||
|
||||
constructor(options, readyCallback) { |
||||
// Check options format
|
||||
if (!options) throw Error('No options passed to generator'); |
||||
if (!options.path) throw Error('No dictionary path specified in options'); |
||||
|
||||
// Load dictionary
|
||||
fs.readFile(options.path, 'utf8', (err, data) => { |
||||
if (err) throw err; |
||||
|
||||
this.dictionary = data.split(/[\n\r]+/); |
||||
|
||||
if (readyCallback) readyCallback(); |
||||
}); |
||||
} |
||||
|
||||
// Generates a dictionary-based key, of keyLength words
|
||||
createKey(keyLength) { |
||||
let text = ''; |
||||
|
||||
for (let i = 0; i < keyLength; i++) { |
||||
const index = Math.floor(Math.random() * this.dictionary.length); |
||||
text += this.dictionary[index]; |
||||
} |
||||
|
||||
return text; |
||||
} |
||||
|
||||
}; |
@ -1,27 +1,33 @@ |
||||
// Draws inspiration from pwgen and http://tools.arantius.com/password
|
||||
|
||||
const randOf = (collection) => { |
||||
return () => { |
||||
return collection[Math.floor(Math.random() * collection.length)]; |
||||
}; |
||||
var PhoneticKeyGenerator = function(options) { |
||||
// No options
|
||||
}; |
||||
|
||||
// Helper methods to get an random vowel or consonant
|
||||
const randVowel = randOf('aeiou'); |
||||
const randConsonant = randOf('bcdfghjklmnpqrstvwxyz'); |
||||
|
||||
module.exports = class PhoneticKeyGenerator { |
||||
|
||||
// Generate a phonetic key of alternating consonant & vowel
|
||||
createKey(keyLength) { |
||||
let text = ''; |
||||
const start = Math.round(Math.random()); |
||||
|
||||
for (let i = 0; i < keyLength; i++) { |
||||
text += (i % 2 == start) ? randConsonant() : randVowel(); |
||||
// Generate a phonetic key
|
||||
PhoneticKeyGenerator.prototype.createKey = function(keyLength) { |
||||
var text = ''; |
||||
var start = Math.round(Math.random()); |
||||
for (var i = 0; i < keyLength; i++) { |
||||
text += (i % 2 == start) ? this.randConsonant() : this.randVowel(); |
||||
} |
||||
|
||||
return text; |
||||
} |
||||
}; |
||||
|
||||
PhoneticKeyGenerator.consonants = 'bcdfghjklmnpqrstvwxyz'; |
||||
PhoneticKeyGenerator.vowels = 'aeiou'; |
||||
|
||||
// Get an random vowel
|
||||
PhoneticKeyGenerator.prototype.randVowel = function() { |
||||
return PhoneticKeyGenerator.vowels[ |
||||
Math.floor(Math.random() * PhoneticKeyGenerator.vowels.length) |
||||
]; |
||||
}; |
||||
|
||||
// Get an random consonant
|
||||
PhoneticKeyGenerator.prototype.randConsonant = function() { |
||||
return PhoneticKeyGenerator.consonants[ |
||||
Math.floor(Math.random() * PhoneticKeyGenerator.consonants.length) |
||||
]; |
||||
}; |
||||
|
||||
module.exports = PhoneticKeyGenerator; |
||||
|
@ -1,20 +1,19 @@ |
||||
module.exports = class RandomKeyGenerator { |
||||
|
||||
// Initialize a new generator with the given keySpace
|
||||
constructor(options = {}) { |
||||
this.keyspace = options.keyspace || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
||||
var RandomKeyGenerator = function(options) { |
||||
if (!options) { |
||||
options = {}; |
||||
} |
||||
this.keyspace = options.keyspace || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
||||
}; |
||||
|
||||
// Generate a key of the given length
|
||||
createKey(keyLength) { |
||||
// Generate a random key
|
||||
RandomKeyGenerator.prototype.createKey = function(keyLength) { |
||||
var text = ''; |
||||
|
||||
var index; |
||||
for (var i = 0; i < keyLength; i++) { |
||||
const index = Math.floor(Math.random() * this.keyspace.length); |
||||
index = Math.floor(Math.random() * this.keyspace.length); |
||||
text += this.keyspace.charAt(index); |
||||
} |
||||
|
||||
return text; |
||||
} |
||||
|
||||
}; |
||||
|
||||
module.exports = RandomKeyGenerator; |
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,34 +0,0 @@ |
||||
/* global describe, it */ |
||||
|
||||
const assert = require('assert'); |
||||
|
||||
const fs = require('fs'); |
||||
|
||||
const Generator = require('../../lib/key_generators/dictionary'); |
||||
|
||||
describe('DictionaryGenerator', function() { |
||||
describe('options', function() { |
||||
it('should throw an error if given no options', () => { |
||||
assert.throws(() => { |
||||
new Generator(); |
||||
}, Error); |
||||
}); |
||||
|
||||
it('should throw an error if given no path', () => { |
||||
assert.throws(() => { |
||||
new Generator({}); |
||||
}, Error); |
||||
}); |
||||
}); |
||||
describe('generation', function() { |
||||
it('should return a key of the proper number of words from the given dictionary', () => { |
||||
const path = '/tmp/haste-server-test-dictionary'; |
||||
const words = ['cat']; |
||||
fs.writeFileSync(path, words.join('\n')); |
||||
|
||||
const gen = new Generator({path}, () => { |
||||
assert.equal('catcatcat', gen.createKey(3)); |
||||
}); |
||||
}); |
||||
}); |
||||
}); |
@ -1,35 +0,0 @@ |
||||
/* global describe, it */ |
||||
|
||||
const assert = require('assert'); |
||||
|
||||
const Generator = require('../../lib/key_generators/phonetic'); |
||||
|
||||
const vowels = 'aeiou'; |
||||
const consonants = 'bcdfghjklmnpqrstvwxyz'; |
||||
|
||||
describe('PhoneticKeyGenerator', () => { |
||||
describe('generation', () => { |
||||
it('should return a key of the proper length', () => { |
||||
const gen = new Generator(); |
||||
assert.equal(6, gen.createKey(6).length); |
||||
}); |
||||
|
||||
it('should alternate consonants and vowels', () => { |
||||
const gen = new Generator(); |
||||
|
||||
const key = gen.createKey(3); |
||||
|
||||
// if it starts with a consonant, we expect cvc
|
||||
// if it starts with a vowel, we expect vcv
|
||||
if(consonants.includes(key[0])) { |
||||
assert.ok(consonants.includes(key[0])); |
||||
assert.ok(consonants.includes(key[2])); |
||||
assert.ok(vowels.includes(key[1])); |
||||
} else { |
||||
assert.ok(vowels.includes(key[0])); |
||||
assert.ok(vowels.includes(key[2])); |
||||
assert.ok(consonants.includes(key[1])); |
||||
} |
||||
}); |
||||
}); |
||||
}); |
@ -1,24 +0,0 @@ |
||||
/* global describe, it */ |
||||
|
||||
const assert = require('assert'); |
||||
|
||||
const Generator = require('../../lib/key_generators/random'); |
||||
|
||||
describe('RandomKeyGenerator', () => { |
||||
describe('generation', () => { |
||||
it('should return a key of the proper length', () => { |
||||
const gen = new Generator(); |
||||
assert.equal(gen.createKey(6).length, 6); |
||||
}); |
||||
|
||||
it('should use a key from the given keyset if given', () => { |
||||
const gen = new Generator({keyspace: 'A'}); |
||||
assert.equal(gen.createKey(6), 'AAAAAA'); |
||||
}); |
||||
|
||||
it('should not use a key from the given keyset if not given', () => { |
||||
const gen = new Generator({keyspace: 'A'}); |
||||
assert.ok(!gen.createKey(6).includes('B')); |
||||
}); |
||||
}); |
||||
}); |
Loading…
Reference in new issue