Add packages/captcha (untested)

This commit is contained in:
Jerko Steiner 2019-10-22 21:39:39 -05:00
parent 0ae8752e4d
commit cd8044d6a9
9 changed files with 150 additions and 2 deletions

View File

@ -20,7 +20,8 @@
"@rondo.dev/validator": "file:packages/validator", "@rondo.dev/validator": "file:packages/validator",
"@rondo.dev/db": "file:packages/db", "@rondo.dev/db": "file:packages/db",
"@rondo.dev/db-typeorm": "file:packages/db-typeorm", "@rondo.dev/db-typeorm": "file:packages/db-typeorm",
"@rondo.dev/middleware": "file:packages/middleware" "@rondo.dev/middleware": "file:packages/middleware",
"@rondo.dev/captcha": "file:packages/captcha"
}, },
"devDependencies": { "devDependencies": {
"@types/bcrypt": "^3.0.0", "@types/bcrypt": "^3.0.0",

View File

@ -0,0 +1,16 @@
module.exports = {
roots: [
'<rootDir>/src',
],
transform: {
'^.+\\.tsx?$': 'ts-jest',
},
testRegex: '(/__tests__/.*|\\.(test|spec))\\.tsx?$',
moduleFileExtensions: [
'ts',
'tsx',
'js',
'jsx',
],
setupFiles: ['<rootDir>/jest.setup.js'],
}

View File

@ -0,0 +1,4 @@
if (!process.env.LOG) {
process.env.LOG = 'sql:warn'
}
process.chdir(__dirname)

View File

@ -0,0 +1,15 @@
{
"name": "@rondo.dev/captcha",
"version": "0.0.1",
"private": true,
"scripts": {
"test": "jest",
"lint": "tslint --project .",
"compile": "tsc",
"clean": "rm -rf lib/"
},
"dependencies": {},
"main": "lib/index.js",
"module": "esm/index.js",
"types": "lib/index.d.ts"
}

View File

@ -0,0 +1,84 @@
import { spawn } from 'child_process'
import { Request, Response } from 'express'
import { Readable } from 'stream'
export async function audio(req: Request, res: Response) {
// TODO generate random string
const captcha = 'test'
req.session!.captcha = captcha
const speech = await speak('test')
res.type(speech.contentType)
speech.stdout.pipe(res)
}
async function speak(text: string) {
const streams: ReadableWritable[] = [
await espeak(),
await opus(),
]
const last = streams.reduce((prev, proc) => {
prev.stdout.pipe(proc.stdin)
return proc
}, createTextStream(text))
return last
}
interface ReadableProcess {
stdout: NodeJS.ReadableStream
contentType: string
}
interface WritableProcess {
stdin: NodeJS.WritableStream
}
interface ReadableWritable extends ReadableProcess, WritableProcess {
}
export function espeak() {
return run(
'espeak',
['-k', '2', '-s', '90', '--stdin', '--stdout'],
'audio/wav',
)
}
async function opus() {
return run('opusenc', ['-', '-'], 'audio/opus')
}
class TextStream extends Readable {
constructor(text: string) {
super()
this.push(text)
this.push(null)
}
_read() {/* noop */}
}
function createTextStream(text: string): ReadableProcess {
return {
stdout: new TextStream(text),
contentType: 'text/plain',
}
}
async function run(
cmd: string, args: string[], contentType: string,
): Promise<ReadableWritable> {
return new Promise((resolve, reject) => {
const p = spawn(cmd, args)
p.once('error', err => {
console.error(err.stack)
reject(err)
})
if (p.pid) {
resolve({ stdin: p.stdin, stdout: p.stdout, contentType })
}
})
}

View File

@ -0,0 +1,10 @@
import SVGCaptcha from 'svg-captcha'
import { Request, Response } from 'express'
export function image(req: Request, res: Response) {
const { text, data } = SVGCaptcha.create()
req.session!.captcha = text
res.type('svg')
res.status(200)
res.send(data)
}

View File

@ -0,0 +1 @@
export * from './image'

View File

@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "esm"
},
"references": [
]
}

View File

@ -0,0 +1,9 @@
{
"extends": "../tsconfig.common.json",
"compilerOptions": {
"outDir": "lib",
"rootDir": "src"
},
"references": [
]
}