Compare commits
222 Commits
Author | SHA1 | Date |
---|---|---|
|
be5c886c97 | 3 years ago |
|
787d839086 | 3 years ago |
|
9e921d5909 | 3 years ago |
|
68f6fe2b96 | 3 years ago |
|
7286385833 | 3 years ago |
|
3dcc43578b | 3 years ago |
|
1ea6b6e99d | 3 years ago |
|
7c613bc788 | 3 years ago |
|
cb4809195b | 3 years ago |
|
00d84614c2 | 3 years ago |
|
52e7cef7ef | 3 years ago |
|
fbff1bc201 | 3 years ago |
|
7af15cc32d | 4 years ago |
|
7f397ce753 | 4 years ago |
|
8f8b039f65 | 4 years ago |
|
eeaf2d7b18 | 4 years ago |
|
db0b7d6444 | 4 years ago |
|
db6e7603f9 | 4 years ago |
|
ad5d7549d7 | 4 years ago |
|
5d2965ffc5 | 5 years ago |
|
f255928af7 | 5 years ago |
|
a108dbadc5 | 5 years ago |
|
c409aca080 | 5 years ago |
|
219424550b | 5 years ago |
|
f147acb51c | 5 years ago |
|
9a692ed652 | 5 years ago |
|
3a17c86a0f | 5 years ago |
|
677a22987a | 5 years ago |
|
89d912c6ff | 5 years ago |
|
4cac6713ef | 5 years ago |
|
f3b0de745b | 5 years ago |
|
cc8a99752f | 5 years ago |
|
6853d077e7 | 5 years ago |
|
80a2b6f0dd | 5 years ago |
|
4f68b3d7d6 | 5 years ago |
|
ef0ca40533 | 5 years ago |
|
f372ef18de | 5 years ago |
|
181a3a2bfa | 5 years ago |
|
61d08afb3b | 5 years ago |
|
1ba025328d | 5 years ago |
|
a79fb39f54 | 5 years ago |
|
3a72d74537 | 5 years ago |
|
e9ae74b7a9 | 5 years ago |
|
c305e9a83d | 5 years ago |
|
16bce4c83d | 5 years ago |
|
661997cd73 | 5 years ago |
|
159f989d08 | 5 years ago |
|
139df62ec4 | 5 years ago |
|
bae6387bb7 | 5 years ago |
|
bb7b9571a7 | 5 years ago |
|
a4dc29fb2b | 5 years ago |
|
342f56ce1a | 5 years ago |
|
05ecc90764 | 5 years ago |
|
69cf505a90 | 5 years ago |
|
9f41993566 | 5 years ago |
|
5c9311fb85 | 5 years ago |
|
5a8d52a5e3 | 5 years ago |
|
0f145b4444 | 5 years ago |
|
aef4bb5edb | 5 years ago |
|
36c854ef1b | 5 years ago |
|
edd428ff37 | 5 years ago |
|
0612ba001e | 5 years ago |
|
064680003d | 5 years ago |
|
655f2af45a | 5 years ago |
|
ce03749c2f | 5 years ago |
|
f6084b4339 | 5 years ago |
|
9b0a5ff0a3 | 5 years ago |
|
1fff48568f | 6 years ago |
|
b4c666fbcf | 6 years ago |
|
b866c33c93 | 6 years ago |
|
035cf0e91e | 6 years ago |
|
f3838ab4a8 | 7 years ago |
|
bf2b1c957a | 7 years ago |
|
86bbc1899d | 7 years ago |
|
d41d7491d4 | 7 years ago |
|
5fb43eb67c | 7 years ago |
|
1eeef4ede4 | 7 years ago |
|
ebc749c5e0 | 7 years ago |
|
b0bbb72f35 | 7 years ago |
|
2213c3874a | 7 years ago |
|
6ebd72a86c | 7 years ago |
|
b6814a1445 | 7 years ago |
|
e3d18efdc6 | 7 years ago |
|
869fb65738 | 7 years ago |
|
56b939124e | 7 years ago |
|
ee1c1c0856 | 7 years ago |
|
b087ac8dd1 | 7 years ago |
|
d922667f56 | 7 years ago |
|
5f6fefa7a6 | 7 years ago |
|
faa7e679ca | 7 years ago |
|
cd3bf26dbe | 7 years ago |
|
830dc1bc43 | 7 years ago |
|
dc0f151a7f | 7 years ago |
|
7f625e22f7 | 7 years ago |
|
528b7b07a8 | 7 years ago |
|
2b81e67ce7 | 7 years ago |
|
827e7b51b5 | 7 years ago |
|
16d529e935 | 7 years ago |
|
ad7702aaf4 | 7 years ago |
|
f5fbc8d19e | 7 years ago |
|
0a8923bf12 | 7 years ago |
|
4d572a2ec0 | 7 years ago |
|
d9a53d3e6e | 7 years ago |
|
8da37ea5de | 8 years ago |
|
ff0fccd6c2 | 8 years ago |
|
63c4576633 | 8 years ago |
|
b31d143bcd | 8 years ago |
|
0d8aec8d61 | 8 years ago |
|
1f9fdd205d | 8 years ago |
|
cdd0cf3739 | 8 years ago |
|
ba5c6b8d16 | 8 years ago |
|
cfef588283 | 8 years ago |
|
318c5f7ba6 | 8 years ago |
|
ee03e7cd78 | 8 years ago |
|
3b6934e348 | 8 years ago |
|
f161cc33b4 | 8 years ago |
|
40f1f2588e | 8 years ago |
|
e4e025f67e | 8 years ago |
|
e12805a8aa | 8 years ago |
|
e76c845f16 | 8 years ago |
|
072418695e | 8 years ago |
|
584b66bc66 | 8 years ago |
|
f8db455f74 | 8 years ago |
|
f19c5d1049 | 8 years ago |
|
c5b859ec98 | 8 years ago |
|
2ee93a7409 | 8 years ago |
|
bf1dbb68b8 | 8 years ago |
|
cf28e23d8e | 8 years ago |
|
5939dec185 | 8 years ago |
|
3ed1d775ac | 8 years ago |
|
87b1c76aaf | 8 years ago |
|
4599203bdf | 8 years ago |
|
d66bc9a6c4 | 8 years ago |
|
80f0618736 | 8 years ago |
|
ac2bceefbb | 8 years ago |
|
dbf4f6b5dd | 8 years ago |
|
8e9205cecc | 8 years ago |
|
e54a860172 | 8 years ago |
|
5a8697cdd8 | 8 years ago |
|
091ea973a8 | 8 years ago |
|
939b7221ab | 8 years ago |
|
934aaf7f51 | 8 years ago |
|
930e21ccb7 | 9 years ago |
|
eb5c8eef6a | 9 years ago |
|
03dd611a86 | 9 years ago |
|
f24376b192 | 9 years ago |
|
eea359d0ec | 9 years ago |
|
af9a71549b | 9 years ago |
|
3178676fba | 9 years ago |
|
3bdfab8219 | 9 years ago |
|
a3a24d9765 | 9 years ago |
|
8afb53e77e | 9 years ago |
|
d6d9cf40f9 | 9 years ago |
|
1010a142e2 | 9 years ago |
|
d3db5e2a5d | 9 years ago |
|
0209375865 | 9 years ago |
|
00a9d9c312 | 9 years ago |
|
6835eef468 | 9 years ago |
|
4626fd9c8d | 9 years ago |
|
fbb6e63c37 | 9 years ago |
|
84c909a5db | 9 years ago |
|
45e19bc7cc | 10 years ago |
|
233bc6ff16 | 10 years ago |
|
360b325ced | 11 years ago |
|
e93f98112b | 11 years ago |
|
05cb051bc8 | 11 years ago |
|
031cdd738a | 11 years ago |
|
c92ab077c0 | 11 years ago |
|
6c31389327 | 11 years ago |
|
a8d4f3c300 | 11 years ago |
|
ab029eae2f | 11 years ago |
|
447d0aae76 | 11 years ago |
|
4870158430 | 11 years ago |
|
0471b059a0 | 11 years ago |
|
5bbe50b481 | 11 years ago |
|
bda2749879 | 11 years ago |
|
028aa96b13 | 11 years ago |
|
2deda5b68a | 11 years ago |
|
ee7098457e | 11 years ago |
|
7a08960414 | 12 years ago |
|
89909747f1 | 12 years ago |
|
202e695e07 | 12 years ago |
|
48e8e79659 | 12 years ago |
|
abb49f2cf3 | 12 years ago |
|
d1cd2a5213 | 13 years ago |
|
27317844e0 | 13 years ago |
|
ee74e2fa90 | 13 years ago |
|
5d8bd2e6f8 | 13 years ago |
|
cd4c7aeab8 | 13 years ago |
|
e37c3cf1b9 | 13 years ago |
|
8858bab985 | 13 years ago |
|
afb0c332cc | 13 years ago |
|
82c58c5c0c | 13 years ago |
|
46bdd27431 | 13 years ago |
|
1adfba1a37 | 13 years ago |
|
54e55b1b0d | 13 years ago |
|
08d37cc7f7 | 13 years ago |
|
aa781957e8 | 13 years ago |
|
c00477c93c | 13 years ago |
|
035f09ac05 | 13 years ago |
|
36e00bb29e | 13 years ago |
|
10623873e8 | 13 years ago |
|
e536ba1019 | 13 years ago |
|
85fc36d710 | 13 years ago |
|
5d5ae164f3 | 13 years ago |
|
79309c75df | 13 years ago |
|
4b58c8d356 | 13 years ago |
|
8f0d6260b0 | 13 years ago |
|
93a83a35da | 13 years ago |
|
4efc5d47d9 | 13 years ago |
|
ff8ef54e34 | 13 years ago |
|
814a49812a | 13 years ago |
|
e0610bc1be | 13 years ago |
|
962976c204 | 13 years ago |
|
16080bdc16 | 13 years ago |
|
20ce741341 | 13 years ago |
|
13bb094fb3 | 13 years ago |
|
b43a55ffda | 13 years ago |
|
45cbdcce70 | 13 years ago |
|
1950cc8db0 | 13 years ago |
|
90cfe0ec57 | 13 years ago |
|
87e28548b9 | 13 years ago |
39 changed files with 3088 additions and 361 deletions
@ -0,0 +1,8 @@ |
|||||||
|
Dockerfile |
||||||
|
.git |
||||||
|
npm-debug.log |
||||||
|
node_modules |
||||||
|
*.swp |
||||||
|
*.swo |
||||||
|
data |
||||||
|
*.DS_Store |
@ -0,0 +1,2 @@ |
|||||||
|
**/*.min.js |
||||||
|
config.js |
@ -0,0 +1,25 @@ |
|||||||
|
{ |
||||||
|
"env": { |
||||||
|
"es6": true, |
||||||
|
"node": true |
||||||
|
}, |
||||||
|
"extends": "eslint:recommended", |
||||||
|
"rules": { |
||||||
|
"indent": [ |
||||||
|
"error", |
||||||
|
2 |
||||||
|
], |
||||||
|
"linebreak-style": [ |
||||||
|
"error", |
||||||
|
"unix" |
||||||
|
], |
||||||
|
"quotes": [ |
||||||
|
"error", |
||||||
|
"single" |
||||||
|
], |
||||||
|
"semi": [ |
||||||
|
"error", |
||||||
|
"always" |
||||||
|
] |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
* @toptal/site-acquisition-eng |
@ -0,0 +1,30 @@ |
|||||||
|
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 }} |
@ -0,0 +1,68 @@ |
|||||||
|
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"] |
@ -0,0 +1,12 @@ |
|||||||
|
version: '3.0' |
||||||
|
services: |
||||||
|
haste-server: |
||||||
|
build: . |
||||||
|
environment: |
||||||
|
- STORAGE_TYPE=memcached |
||||||
|
- STORAGE_HOST=memcached |
||||||
|
- STORAGE_PORT=11211 |
||||||
|
ports: |
||||||
|
- 7777:7777 |
||||||
|
memcached: |
||||||
|
image: memcached:latest |
@ -0,0 +1,108 @@ |
|||||||
|
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)); |
@ -0,0 +1,9 @@ |
|||||||
|
#!/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 "$@" |
@ -0,0 +1,56 @@ |
|||||||
|
/*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; |
@ -0,0 +1,89 @@ |
|||||||
|
/*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,45 +1,54 @@ |
|||||||
var memcached = require('memcache'); |
const memcached = require('memcached'); |
||||||
var winston = require('winston'); |
const winston = require('winston'); |
||||||
|
|
||||||
// Create a new store with options
|
class MemcachedDocumentStore { |
||||||
var MemcachedDocumentStore = function(options) { |
|
||||||
this.expire = options.expire; |
// Create a new store with options
|
||||||
if (!MemcachedDocumentStore.client) { |
constructor(options) { |
||||||
MemcachedDocumentStore.connect(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); |
||||||
|
} |
||||||
|
|
||||||
|
// 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}); |
||||||
|
}); |
||||||
} |
} |
||||||
}; |
|
||||||
|
// Save file in a key
|
||||||
// Create a connection
|
set(key, data, callback, skipExpire) { |
||||||
MemcachedDocumentStore.connect = function(options) { |
this.client.set(key, data, skipExpire ? 0 : this.expire || 0, (error) => { |
||||||
var host = options.host || '127.0.0.1'; |
callback(!error); |
||||||
var port = options.port || 11211; |
}); |
||||||
this.client = new memcached.Client(port, host); |
} |
||||||
this.client.connect(); |
|
||||||
this.client.on('connect', function() { |
// Get a file from a key
|
||||||
winston.info('connected to memcached on ' + host + ':' + port); |
get(key, callback, skipExpire) { |
||||||
}); |
this.client.get(key, (error, data) => { |
||||||
this.client.on('error', function(e) { |
const value = error ? false : data; |
||||||
winston.info('error connecting to memcached', { error: e }); |
|
||||||
}); |
callback(value); |
||||||
}; |
|
||||||
|
// Update the key so that the expiration is pushed forward
|
||||||
// Save file in a key
|
if (value && !skipExpire) { |
||||||
MemcachedDocumentStore.prototype.set = |
this.set(key, data, (updateSucceeded) => { |
||||||
function(key, data, callback, skipExpire) { |
if (!updateSucceeded) { |
||||||
MemcachedDocumentStore.client.set(key, data, function(err, reply) { |
winston.error('failed to update expiration on GET', {key}); |
||||||
err ? callback(false) : callback(true); |
} |
||||||
}, skipExpire ? 0 : this.expire); |
}, skipExpire); |
||||||
}; |
} |
||||||
|
}); |
||||||
// Get a file from a key
|
} |
||||||
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; |
module.exports = MemcachedDocumentStore; |
||||||
|
@ -0,0 +1,88 @@ |
|||||||
|
|
||||||
|
|
||||||
|
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; |
@ -0,0 +1,80 @@ |
|||||||
|
/*global require,module,process*/ |
||||||
|
|
||||||
|
var winston = require('winston'); |
||||||
|
const {Pool} = require('pg'); |
||||||
|
|
||||||
|
// create table entries (id serial primary key, key varchar(255) not null, value text not null, expiration int, unique(key));
|
||||||
|
|
||||||
|
// A postgres document store
|
||||||
|
var PostgresDocumentStore = function (options) { |
||||||
|
this.expireJS = parseInt(options.expire, 10); |
||||||
|
|
||||||
|
const connectionString = process.env.DATABASE_URL || options.connectionUrl; |
||||||
|
this.pool = new Pool({connectionString}); |
||||||
|
}; |
||||||
|
|
||||||
|
PostgresDocumentStore.prototype = { |
||||||
|
|
||||||
|
// Set a given key
|
||||||
|
set: function (key, data, callback, skipExpire) { |
||||||
|
var now = Math.floor(new Date().getTime() / 1000); |
||||||
|
var that = this; |
||||||
|
this.safeConnect(function (err, client, done) { |
||||||
|
if (err) { return callback(false); } |
||||||
|
client.query('INSERT INTO entries (key, value, expiration) VALUES ($1, $2, $3)', [ |
||||||
|
key, |
||||||
|
data, |
||||||
|
that.expireJS && !skipExpire ? that.expireJS + now : null |
||||||
|
], function (err) { |
||||||
|
if (err) { |
||||||
|
winston.error('error persisting value to postgres', { error: err }); |
||||||
|
return callback(false); |
||||||
|
} |
||||||
|
callback(true); |
||||||
|
done(); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
// Get a given key's data
|
||||||
|
get: function (key, callback, skipExpire) { |
||||||
|
var now = Math.floor(new Date().getTime() / 1000); |
||||||
|
var that = this; |
||||||
|
this.safeConnect(function (err, client, done) { |
||||||
|
if (err) { return callback(false); } |
||||||
|
client.query('SELECT id,value,expiration from entries where KEY = $1 and (expiration IS NULL or expiration > $2)', [key, now], function (err, result) { |
||||||
|
if (err) { |
||||||
|
winston.error('error retrieving value from postgres', { error: err }); |
||||||
|
return callback(false); |
||||||
|
} |
||||||
|
callback(result.rows.length ? result.rows[0].value : false); |
||||||
|
if (result.rows.length && that.expireJS && !skipExpire) { |
||||||
|
client.query('UPDATE entries SET expiration = $1 WHERE ID = $2', [ |
||||||
|
that.expireJS + now, |
||||||
|
result.rows[0].id |
||||||
|
], function (err) { |
||||||
|
if (!err) { |
||||||
|
done(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
done(); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
// A connection wrapper
|
||||||
|
safeConnect: function (callback) { |
||||||
|
this.pool.connect((error, client, done) => { |
||||||
|
if (error) { |
||||||
|
winston.error('error connecting to postgres', {error}); |
||||||
|
callback(error); |
||||||
|
} else { |
||||||
|
callback(undefined, client, done); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
module.exports = PostgresDocumentStore; |
@ -0,0 +1,46 @@ |
|||||||
|
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; |
@ -0,0 +1,32 @@ |
|||||||
|
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,32 +1,27 @@ |
|||||||
// Draws inspiration from pwgen and http://tools.arantius.com/password
|
// Draws inspiration from pwgen and http://tools.arantius.com/password
|
||||||
var PhoneticKeyGenerator = function(options) { |
|
||||||
// No options
|
|
||||||
}; |
|
||||||
|
|
||||||
// Generate a phonetic key
|
const randOf = (collection) => { |
||||||
PhoneticKeyGenerator.prototype.createKey = function(keyLength) { |
return () => { |
||||||
var text = ''; |
return collection[Math.floor(Math.random() * collection.length)]; |
||||||
for (var i = 0; i < keyLength; i++) { |
}; |
||||||
text += (i % 2 == 0) ? this.randConsonant() : this.randVowel(); |
|
||||||
} |
|
||||||
return text; |
|
||||||
}; |
}; |
||||||
|
|
||||||
PhoneticKeyGenerator.consonants = 'bcdfghjklmnpqrstvwxy'; |
// Helper methods to get an random vowel or consonant
|
||||||
PhoneticKeyGenerator.vowels = 'aeiou'; |
const randVowel = randOf('aeiou'); |
||||||
|
const randConsonant = randOf('bcdfghjklmnpqrstvwxyz'); |
||||||
|
|
||||||
// Get an random vowel
|
module.exports = class PhoneticKeyGenerator { |
||||||
PhoneticKeyGenerator.prototype.randVowel = function() { |
|
||||||
return PhoneticKeyGenerator.vowels[ |
|
||||||
Math.floor(Math.random() * PhoneticKeyGenerator.vowels.length) |
|
||||||
]; |
|
||||||
}; |
|
||||||
|
|
||||||
// Get an random consonant
|
// Generate a phonetic key of alternating consonant & vowel
|
||||||
PhoneticKeyGenerator.prototype.randConsonant = function() { |
createKey(keyLength) { |
||||||
return PhoneticKeyGenerator.consonants[ |
let text = ''; |
||||||
Math.floor(Math.random() * PhoneticKeyGenerator.consonants.length) |
const start = Math.round(Math.random()); |
||||||
]; |
|
||||||
}; |
|
||||||
|
|
||||||
module.exports = PhoneticKeyGenerator; |
for (let i = 0; i < keyLength; i++) { |
||||||
|
text += (i % 2 == start) ? randConsonant() : randVowel(); |
||||||
|
} |
||||||
|
|
||||||
|
return text; |
||||||
|
} |
||||||
|
|
||||||
|
}; |
||||||
|
@ -1,19 +1,20 @@ |
|||||||
var RandomKeyGenerator = function(options) { |
module.exports = class RandomKeyGenerator { |
||||||
if (!options) { |
|
||||||
options = {}; |
// Initialize a new generator with the given keySpace
|
||||||
|
constructor(options = {}) { |
||||||
|
this.keyspace = options.keyspace || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
||||||
} |
} |
||||||
this.keyspace = options.keyspace || 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; |
|
||||||
}; |
|
||||||
|
|
||||||
// Generate a random key
|
// Generate a key of the given length
|
||||||
RandomKeyGenerator.prototype.createKey = function(keyLength) { |
createKey(keyLength) { |
||||||
var text = ''; |
var text = ''; |
||||||
var index; |
|
||||||
for (var i = 0; i < keyLength; i++) { |
for (var i = 0; i < keyLength; i++) { |
||||||
index = Math.floor(Math.random() * this.keyspace.length); |
const index = Math.floor(Math.random() * this.keyspace.length); |
||||||
text += this.keyspace.charAt(index); |
text += this.keyspace.charAt(index); |
||||||
|
} |
||||||
|
|
||||||
|
return text; |
||||||
} |
} |
||||||
return text; |
|
||||||
}; |
|
||||||
|
|
||||||
module.exports = RandomKeyGenerator; |
}; |
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,52 +1,47 @@ |
|||||||
{ |
{ |
||||||
|
"name": "haste", |
||||||
"name": "haste", |
"version": "0.1.0", |
||||||
"version": "0.0.1", |
"private": true, |
||||||
|
"description": "Private Pastebin Server", |
||||||
"private": true, |
"keywords": [ |
||||||
|
"paste", |
||||||
"description": "Private Paste", |
"pastebin" |
||||||
|
], |
||||||
"keywords": [ "paste", "pastebin" ], |
"author": { |
||||||
|
"name": "John Crepezzi", |
||||||
"author": { |
"email": "john.crepezzi@gmail.com", |
||||||
"name": "John Crepezzi", |
"url": "http://seejohncode.com/" |
||||||
"email": "john.crepezzi@gmail.com", |
|
||||||
"url": "http://seejohncode.com/" |
|
||||||
}, |
|
||||||
|
|
||||||
"main": "haste", |
|
||||||
|
|
||||||
"dependencies": { |
|
||||||
"winston": "*", |
|
||||||
"connect": "*", |
|
||||||
"uglify-js": "*" |
|
||||||
}, |
|
||||||
|
|
||||||
"devDependencies": { |
|
||||||
"mocha": "*", |
|
||||||
"should": "*" |
|
||||||
}, |
}, |
||||||
|
"main": "haste", |
||||||
"bundledDependencies": [], |
"dependencies": { |
||||||
|
"busboy": "0.2.4", |
||||||
"engines": { |
"connect": "^3.7.0", |
||||||
"node": "*" |
"connect-ratelimit": "0.0.7", |
||||||
}, |
"connect-route": "0.1.5", |
||||||
|
"pg": "^8.0.0", |
||||||
"bin": { |
"redis": "0.8.1", |
||||||
"haste-server": "./server.js" |
"redis-url": "0.1.0", |
||||||
}, |
"st": "^2.0.0", |
||||||
|
"uglify-js": "3.1.6", |
||||||
"files": [ "server.js", "lib", "static" ], |
"winston": "^2.0.0" |
||||||
|
}, |
||||||
"directories": { |
"devDependencies": { |
||||||
"lib": "./lib" |
"mocha": "^8.1.3" |
||||||
}, |
}, |
||||||
|
"bundledDependencies": [], |
||||||
"scripts": { |
"bin": { |
||||||
"start": "node server.js", |
"haste-server": "./server.js" |
||||||
"test": "mocha -r should spec/*" |
}, |
||||||
} |
"files": [ |
||||||
|
"server.js", |
||||||
|
"lib", |
||||||
|
"static" |
||||||
|
], |
||||||
|
"directories": { |
||||||
|
"lib": "./lib" |
||||||
|
}, |
||||||
|
"scripts": { |
||||||
|
"start": "node server.js", |
||||||
|
"test": "mocha --recursive" |
||||||
|
} |
||||||
} |
} |
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,34 @@ |
|||||||
|
/* 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)); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
@ -0,0 +1,35 @@ |
|||||||
|
/* 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])); |
||||||
|
} |
||||||
|
}); |
||||||
|
}); |
||||||
|
}); |
@ -0,0 +1,24 @@ |
|||||||
|
/* 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