1
0
Fork 0
mirror of https://github.com/seejohnrun/haste-server.git synced 2024-11-01 03:21:21 +00:00

fix code, readme and lint

This commit is contained in:
Yusuf Yilmaz 2022-06-08 11:26:32 +02:00
parent 42c60c64c2
commit 350abbdf3b
14 changed files with 158 additions and 153 deletions

View file

@ -1,6 +1,6 @@
module.exports = { module.exports = {
env: { env: {
node: true, node: true
}, },
extends: [ extends: [
'eslint:recommended', 'eslint:recommended',
@ -10,47 +10,44 @@ module.exports = {
'plugin:import/errors', 'plugin:import/errors',
'plugin:import/warnings', 'plugin:import/warnings',
'plugin:import/typescript', 'plugin:import/typescript',
'prettier', 'prettier'
],
plugins: [
'import',
'@typescript-eslint'
], ],
plugins: ['import', '@typescript-eslint'],
settings: { settings: {
'import/parsers': { 'import/parsers': {
'@typescript-eslint/parser': ['.ts'], '@typescript-eslint/parser': ['.ts']
}, },
'import/resolver': { 'import/resolver': {
node: { node: {
extensions: ['.js', '.ts'], extensions: ['.js', '.ts'],
moduleDirectory: ['node_modules', 'src/'], moduleDirectory: ['node_modules', 'src/']
}, },
typescript: { typescript: {
alwaysTryTypes: true, alwaysTryTypes: true,
project: '.', project: '.'
}, }
}, }
}, },
overrides: [ overrides: [
{ {
env: { env: {
jest: true, jest: true
}, },
files: ['**/__tests__/**/*.[jt]s', '**/?(*.)+(spec|test).[jt]s'], files: ['**/__tests__/**/*.[jt]s', '**/?(*.)+(spec|test).[jt]s'],
extends: ['plugin:jest/recommended'], extends: ['plugin:jest/recommended'],
rules: { rules: {
'import/no-extraneous-dependencies': [ 'import/no-extraneous-dependencies': [
'off', 'off',
{ devDependencies: ['**/?(*.)+(spec|test).[jt]s'] }, { devDependencies: ['**/?(*.)+(spec|test).[jt]s'] }
], ],
camelcase: ['off'], camelcase: ['off']
}, }
}, }
], ],
ignorePatterns: ['**/*.js', 'node_modules', 'dist'], ignorePatterns: ['**/*.js', 'node_modules', 'dist'],
parserOptions: { parserOptions: {
root: true, root: true,
tsconfigRootDir: __dirname, tsconfigRootDir: __dirname,
project: ['./tsconfig.json'], project: ['./tsconfig.json']
}, }
} }

View file

@ -2,7 +2,7 @@ name: Close inactive issues and PRs
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: "30 1 * * *" - cron: '30 1 * * *'
jobs: jobs:
close-stale: close-stale:
@ -15,16 +15,16 @@ jobs:
with: with:
days-before-stale: 30 days-before-stale: 30
days-before-close: 14 days-before-close: 14
stale-issue-label: "stale" stale-issue-label: 'stale'
stale-pr-label: "stale" stale-pr-label: 'stale'
exempt-issue-labels: backlog,triage,nostale exempt-issue-labels: backlog,triage,nostale
exempt-pr-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." 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." 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." 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." 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 }} repo-token: ${{ secrets.GITHUB_TOKEN }}

2
.prettierignore Normal file
View file

@ -0,0 +1,2 @@
static
/node_modules

View file

@ -7,9 +7,9 @@ version can be found at [hastebin.com](http://hastebin.com)
Major design objectives: Major design objectives:
* Be really pretty - Be really pretty
* Be really simple - Be really simple
* Be easy to set up and use - Be easy to set up and use
Haste works really well with a little utility called Haste works really well with a little utility called
[haste-client](https://github.com/seejohnrun/haste-client), allowing you [haste-client](https://github.com/seejohnrun/haste-client), allowing you
@ -22,54 +22,54 @@ STDOUT. Check the README there for more details and usages.
## Tested Browsers ## Tested Browsers
* Firefox 8 - Firefox 8
* Chrome 17 - Chrome 17
* Safari 5.3 - Safari 5.3
## Installation ## Installation
1. Download the package, and expand it 1. Download the package, and expand it
3. `yarn add` 2. `yarn`
## Running the project ## Running the project
> Explore the settings inside of config.js, but the defaults should be good > Explore the settings inside of project-config.js, but the defaults should be good
### Development ### Development
1. `yarn add` 1. `yarn`
2. `yarn dev` (you may specify an optional `<config-path>` as well) 2. `yarn dev` (you may specify an optional `<config-path>` as well)
### Production ### Production
1. `yarn add` 1. `yarn`
2. `yarn build` to build the package 2. `yarn build` to build the package
3. `yarn start` to start the server 3. `yarn start` to start the server
### Production with Docker ### Production with Docker
1. `docker compose up` 1. `docker-compose up`
## Settings ## Settings
* `host` - the host the server runs on (default localhost) - `host` - the host the server runs on (default localhost)
* `port` - the port the server runs on (default 7777) - `port` - the port the server runs on (default 7777)
* `keyLength` - the length of the keys to user (default 10) - `keyLength` - the length of the keys to user (default 10)
* `maxLength` - maximum length of a paste (default 400000) - `maxLength` - maximum length of a paste (default 400000)
* `staticMaxAge` - max age for static assets (86400) - `staticMaxAge` - max age for static assets (86400)
* `recompressStaticAssets` - whether or not to compile static js assets (true) - `recompressStaticAssets` - whether or not to compile static js assets (true)
* `documents` - static documents to serve (ex: http://hastebin.com/about.com) - `documents` - static documents to serve (ex: http://hastebin.com/about.com)
in addition to static assets. These will never expire. in addition to static assets. These will never expire.
* `storage` - storage options (see below) - `storage` - storage options (see below)
* `logging` - logging preferences - `logging` - logging preferences
* `keyGenerator` - key generator options (see below) - `keyGenerator` - key generator options (see below)
* `rateLimits` - settings for rate limiting (see below) - `rateLimits` - settings for rate limiting (see below)
## Rate Limiting ## Rate Limiting
When present, the `rateLimits` option enables built-in rate limiting courtesy When present, the `rateLimits` option enables built-in rate limiting courtesy
of `connect-ratelimit`. Any of the options supported by that library can be of `connect-ratelimit`. Any of the options supported by that library can be
used and set in `config.js`. used and set in `project-config.js`.
See the README for [connect-ratelimit](https://github.com/dharmafly/connect-ratelimit) See the README for [connect-ratelimit](https://github.com/dharmafly/connect-ratelimit)
for more information! for more information!
@ -104,7 +104,7 @@ for the key.
### File ### File
To use file storage (the default) change the storage section in `config.js` to To use file storage (the default) change the storage section in `project-config.js` to
something like: something like:
```json ```json
@ -280,10 +280,7 @@ your bucket:
"Version": "2012-10-17", "Version": "2012-10-17",
"Statement": [ "Statement": [
{ {
"Action": [ "Action": ["s3:GetObject", "s3:PutObject"],
"s3:GetObject",
"s3:PutObject"
],
"Effect": "Allow", "Effect": "Allow",
"Resource": "arn:aws:s3:::your-bucket-name-goes-here/*" "Resource": "arn:aws:s3:::your-bucket-name-goes-here/*"
} }
@ -401,6 +398,6 @@ SOFTWARE
### Other components: ### Other components:
* jQuery: MIT/GPL license - jQuery: MIT/GPL license
* highlight.js: Copyright © 2006, Ivan Sagalaev - highlight.js: Copyright © 2006, Ivan Sagalaev
* highlightjs-coffeescript: WTFPL - Copyright © 2011, Dmytrii Nagirniak - highlightjs-coffeescript: WTFPL - Copyright © 2011, Dmytrii Nagirniak

View file

@ -24,17 +24,18 @@ and send it to people.
You can even take this a step further, and cut out the last step of copying the You can even take this a step further, and cut out the last step of copying the
URL with: URL with:
* osx: `cat something | haste | pbcopy` - osx: `cat something | haste | pbcopy`
* linux: `cat something | haste | xsel` - linux: `cat something | haste | xsel`
* windows: check out [WinHaste](https://github.com/ajryan/WinHaste) - windows: check out [WinHaste](https://github.com/ajryan/WinHaste)
After running that, the STDOUT output of `cat something` will show up at a URL After running that, the STDOUT output of `cat something` will show up at a URL
which has been conveniently copied to your clipboard. which has been conveniently copied to your clipboard.
That's all there is to that, and you can install it with `gem install haste` That's all there is to that, and you can install it with `gem install haste`
right now. right now.
* osx: you will need to have an up to date version of Xcode
* linux: you will need to have rubygems and ruby-devel installed - osx: you will need to have an up to date version of Xcode
- linux: you will need to have rubygems and ruby-devel installed
## Duration ## Duration
@ -52,8 +53,8 @@ pastes.
Haste can easily be installed behind your network, and it's all open source! Haste can easily be installed behind your network, and it's all open source!
* [haste-client](https://github.com/seejohnrun/haste-client) - [haste-client](https://github.com/seejohnrun/haste-client)
* [haste-server](https://github.com/seejohnrun/haste-server) - [haste-server](https://github.com/seejohnrun/haste-server)
## Author ## Author

View file

@ -5,10 +5,8 @@ module.exports = {
rootDir: '../', rootDir: '../',
testRegex: '\\.test\\.ts$', testRegex: '\\.test\\.ts$',
reporters: ['default'], reporters: ['default'],
roots: [ roots: ['test'],
"test"
],
moduleNameMapper: { moduleNameMapper: {
"src/(.*)": "<rootDir>/src/$1" 'src/(.*)': '<rootDir>/src/$1'
} }
} }

View file

@ -28,8 +28,8 @@ const {
RATE_LIMITS_BLACKLIST_TOTAL_REQUESTS, RATE_LIMITS_BLACKLIST_TOTAL_REQUESTS,
RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS, RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS,
RATE_LIMITS_BLACKLIST, RATE_LIMITS_BLACKLIST,
DOCUMENTS, DOCUMENTS
} = process.env; } = process.env
const config = { const config = {
host: HOST, host: HOST,
@ -47,29 +47,29 @@ const config = {
{ {
level: LOGGING_LEVEL, level: LOGGING_LEVEL,
type: LOGGING_TYPE, type: LOGGING_TYPE,
colorize: LOGGING_COLORIZE, colorize: LOGGING_COLORIZE
}, }
], ],
keyGenerator: { keyGenerator: {
type: KEYGENERATOR_TYPE, type: KEYGENERATOR_TYPE,
keyspace: KEY_GENERATOR_KEYSPACE, keyspace: KEY_GENERATOR_KEYSPACE
}, },
rateLimits: { rateLimits: {
whitelist: RATE_LIMITS_WHITELIST ? RATE_LIMITS_WHITELIST.split(",") : [], whitelist: RATE_LIMITS_WHITELIST ? RATE_LIMITS_WHITELIST.split(',') : [],
blacklist: RATE_LIMITS_BLACKLIST ? RATE_LIMITS_BLACKLIST.split(",") : [], blacklist: RATE_LIMITS_BLACKLIST ? RATE_LIMITS_BLACKLIST.split(',') : [],
categories: { categories: {
normal: { normal: {
totalRequests: RATE_LIMITS_NORMAL_TOTAL_REQUESTS, totalRequests: RATE_LIMITS_NORMAL_TOTAL_REQUESTS,
every: RATE_LIMITS_NORMAL_EVERY_MILLISECONDS, every: RATE_LIMITS_NORMAL_EVERY_MILLISECONDS
}, },
whitelist: whitelist:
RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS || RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS ||
RATE_LIMITS_WHITELIST_TOTAL_REQUESTS RATE_LIMITS_WHITELIST_TOTAL_REQUESTS
? { ? {
totalRequests: RATE_LIMITS_WHITELIST_TOTAL_REQUESTS, totalRequests: RATE_LIMITS_WHITELIST_TOTAL_REQUESTS,
every: RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS, every: RATE_LIMITS_WHITELIST_EVERY_MILLISECONDS
} }
: null, : null,
blacklist: blacklist:
@ -77,10 +77,10 @@ const config = {
RATE_LIMITS_BLACKLIST_TOTAL_REQUESTS RATE_LIMITS_BLACKLIST_TOTAL_REQUESTS
? { ? {
totalRequests: RATE_LIMITS_WHITELIST_TOTAL_REQUESTS, totalRequests: RATE_LIMITS_WHITELIST_TOTAL_REQUESTS,
every: RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS, every: RATE_LIMITS_BLACKLIST_EVERY_MILLISECONDS
}
: null
} }
: null,
},
}, },
storage: { storage: {
@ -94,15 +94,15 @@ const config = {
db: STORAGE_DB, db: STORAGE_DB,
user: STORAGE_USERNAME, user: STORAGE_USERNAME,
password: STORAGE_PASSWORD, password: STORAGE_PASSWORD,
path: STORAGE_FILEPATH, path: STORAGE_FILEPATH
}, },
documents: DOCUMENTS documents: DOCUMENTS
? DOCUMENTS.split(",").reduce((acc, item) => { ? DOCUMENTS.split(',').reduce((acc, item) => {
const keyAndValueArray = item.replace(/\s/g, "").split("="); const keyAndValueArray = item.replace(/\s/g, '').split('=')
return { ...acc, [keyAndValueArray[0]]: keyAndValueArray[1] }; return { ...acc, [keyAndValueArray[0]]: keyAndValueArray[1] }
}, {}) }, {})
: null, : null
}; }
console.log(JSON.stringify(config)); console.log(JSON.stringify(config))

View file

@ -95,6 +95,6 @@
"dev": "nodemon", "dev": "nodemon",
"lint": "eslint src --fix", "lint": "eslint src --fix",
"types:check": "tsc --noEmit --pretty", "types:check": "tsc --noEmit --pretty",
"pretty": "prettier --write src" "pretty": "prettier --write ."
} }
} }

View file

@ -12,7 +12,7 @@ class DocumentHandler {
maxLength?: number maxLength?: number
public store: Store store: Store
keyGenerator: KeyGenerator keyGenerator: KeyGenerator
@ -55,7 +55,7 @@ class DocumentHandler {
) )
} }
public handlePost(request: Request, response: Response) { handlePost(request: Request, response: Response) {
// const this = this // const this = this
let buffer = '' let buffer = ''
let cancelled = false let cancelled = false
@ -121,7 +121,7 @@ class DocumentHandler {
} }
} }
public handleRawGet(request: Request, response: Response) { handleRawGet(request: Request, response: Response) {
const key = request.params.id.split('.')[0] const key = request.params.id.split('.')[0]
const skipExpire = !!this.config.documents[key] const skipExpire = !!this.config.documents[key]

View file

@ -23,29 +23,29 @@ export type BaseStoreConfig = {
export interface MongoStoreConfig extends BaseStoreConfig { export interface MongoStoreConfig extends BaseStoreConfig {
connectionUrl: string connectionUrl: string
type: StoreNames.mongo type: StoreNames.Mongo
} }
export interface MemcachedStoreConfig extends BaseStoreConfig { export interface MemcachedStoreConfig extends BaseStoreConfig {
host: string host: string
port: number port: number
type: StoreNames.memcached type: StoreNames.Memcached
} }
export interface FileStoreConfig extends BaseStoreConfig { export interface FileStoreConfig extends BaseStoreConfig {
path: string path: string
type: StoreNames.file type: StoreNames.File
} }
export interface AmazonStoreConfig extends BaseStoreConfig { export interface AmazonStoreConfig extends BaseStoreConfig {
bucket: string bucket: string
region: string region: string
type: StoreNames.amazons3 type: StoreNames.AmazonS3
} }
export interface PostgresStoreConfig extends BaseStoreConfig { export interface PostgresStoreConfig extends BaseStoreConfig {
connectionUrl: string connectionUrl: string
type: StoreNames.postgres type: StoreNames.Postgres
} }
export interface RethinkDbStoreConfig extends BaseStoreConfig { export interface RethinkDbStoreConfig extends BaseStoreConfig {
@ -54,7 +54,7 @@ export interface RethinkDbStoreConfig extends BaseStoreConfig {
db: string db: string
user: string user: string
password: string password: string
type: StoreNames.rethinkdb type: StoreNames.RethinkDb
} }
export interface RedisStoreConfig extends BaseStoreConfig { export interface RedisStoreConfig extends BaseStoreConfig {
@ -65,11 +65,11 @@ export interface RedisStoreConfig extends BaseStoreConfig {
password?: string password?: string
host?: string host?: string
port?: string port?: string
type: StoreNames.redis type: StoreNames.Redis
} }
export interface GoogleStoreConfig extends BaseStoreConfig { export interface GoogleStoreConfig extends BaseStoreConfig {
type: StoreNames.googledatastore type: StoreNames.GoogleDataStore
} }
export type StoreConfig = export type StoreConfig =

View file

@ -1,11 +1,11 @@
// eslint-disable-next-line import/prefer-default-export // eslint-disable-next-line import/prefer-default-export
export enum StoreNames { export enum StoreNames {
amazons3 = 'amazon-s3', AmazonS3 = 'amazon-s3',
file = 'file', File = 'file',
googledatastore = 'google-datastore', GoogleDataStore = 'google-datastore',
memcached = 'memcached', Memcached = 'memcached',
mongo = 'mongo', Mongo = 'mongo',
postgres = 'postgres', Postgres = 'postgres',
redis = 'redis', Redis = 'redis',
rethinkdb = 'rethinkdb' RethinkDb = 'rethinkdb'
} }

View file

@ -1,25 +1,35 @@
import { createMock } from 'ts-auto-mock'; import { createMock } from 'ts-auto-mock'
import DocumentHandler from 'src/lib/document-handler/index' import DocumentHandler from 'src/lib/document-handler/index'
import Generator from 'src/lib/key-generators/random' import Generator from 'src/lib/key-generators/random'
import constants from 'src/constants' import constants from 'src/constants'
import { Config } from 'src/types/config' import { Config } from 'src/types/config'
import { Store } from 'src/lib/document-stores'; import { Store } from 'src/lib/document-stores'
const store : Store = createMock<Store>(); const store: Store = createMock<Store>()
const config : Config = createMock<Config>(); const config: Config = createMock<Config>()
describe('document-handler', () => { describe('document-handler', () => {
describe('with random key', () => { describe('with random key', () => {
it('should choose a key of the proper length', () => { it('should choose a key of the proper length', () => {
const gen = new Generator({ type: 'random' }) const gen = new Generator({ type: 'random' })
const dh = new DocumentHandler({ keyLength: 6, keyGenerator: gen, store, config}) const dh = new DocumentHandler({
expect(dh.acceptableKey()?.length).toEqual(6); keyLength: 6,
keyGenerator: gen,
store,
config
})
expect(dh.acceptableKey()?.length).toEqual(6)
}) })
it('should choose a default key length', () => { it('should choose a default key length', () => {
const gen = new Generator({ type: 'random' }) const gen = new Generator({ type: 'random' })
const dh = new DocumentHandler({ keyGenerator: gen, maxLength: 1, store, config }) const dh = new DocumentHandler({
expect(dh.keyLength).toEqual(constants.DEFAULT_KEY_LENGTH); keyGenerator: gen,
maxLength: 1,
store,
config
})
expect(dh.keyLength).toEqual(constants.DEFAULT_KEY_LENGTH)
}) })
}) })
}) })

View file

@ -14,7 +14,7 @@ describe('Redis document store', () => {
it('should be able to set a key and have an expiration set', async () => { it('should be able to set a key and have an expiration set', async () => {
store = new RedisDocumentStore({ store = new RedisDocumentStore({
expire: 10, expire: 10,
type: StoreNames.redis type: StoreNames.Redis
}) })
return store.set('hello1', 'world', async () => { return store.set('hello1', 'world', async () => {
const res = await store.client?.ttl('hello1') const res = await store.client?.ttl('hello1')
@ -25,7 +25,7 @@ describe('Redis document store', () => {
it('should not set an expiration when told not to', async () => { it('should not set an expiration when told not to', async () => {
store = new RedisDocumentStore({ store = new RedisDocumentStore({
expire: 10, expire: 10,
type: StoreNames.redis type: StoreNames.Redis
}) })
store.set( store.set(
@ -41,7 +41,7 @@ describe('Redis document store', () => {
it('should not set an expiration when expiration is off', async () => { it('should not set an expiration when expiration is off', async () => {
store = new RedisDocumentStore({ store = new RedisDocumentStore({
type: StoreNames.redis type: StoreNames.Redis
}) })
store.set('hello3', 'world', async () => { store.set('hello3', 'world', async () => {

View file

@ -1,19 +1,19 @@
/* eslint-disable jest/no-conditional-expect */ /* eslint-disable jest/no-conditional-expect */
import Generator from 'src/lib/key-generators/phonetic' import Generator from 'src/lib/key-generators/phonetic'
const vowels = 'aeiou'; const vowels = 'aeiou'
const consonants = 'bcdfghjklmnpqrstvwxyz'; const consonants = 'bcdfghjklmnpqrstvwxyz'
describe('PhoneticKeyGenerator', () => { describe('PhoneticKeyGenerator', () => {
describe('generation', () => { describe('generation', () => {
it('should return a key of the proper length', () => { it('should return a key of the proper length', () => {
const gen = new Generator({ type: 'phonetic'}); const gen = new Generator({ type: 'phonetic' })
expect(gen.createKey(6).length).toEqual(6); expect(gen.createKey(6).length).toEqual(6)
}); })
it('should alternate consonants and vowels', () => { it('should alternate consonants and vowels', () => {
const gen = new Generator({ type: 'phonetic'}); const gen = new Generator({ type: 'phonetic' })
const key = gen.createKey(3); const key = gen.createKey(3)
// if it starts with a consonant, we expect cvc // if it starts with a consonant, we expect cvc
// if it starts with a vowel, we expect vcv // if it starts with a vowel, we expect vcv
if (consonants.includes(key[0])) { if (consonants.includes(key[0])) {
@ -25,6 +25,6 @@ describe('PhoneticKeyGenerator', () => {
expect(vowels.includes(key[2])).toBeTruthy() expect(vowels.includes(key[2])).toBeTruthy()
expect(consonants.includes(key[1])).toBeTruthy() expect(consonants.includes(key[1])).toBeTruthy()
} }
}); })
}); })
}); })