Add packages/captcha (untested)
This commit is contained in:
parent
0ae8752e4d
commit
cd8044d6a9
@ -20,7 +20,8 @@
|
||||
"@rondo.dev/validator": "file:packages/validator",
|
||||
"@rondo.dev/db": "file:packages/db",
|
||||
"@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": {
|
||||
"@types/bcrypt": "^3.0.0",
|
||||
|
||||
16
packages/captcha/jest.config.js
Normal file
16
packages/captcha/jest.config.js
Normal 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'],
|
||||
}
|
||||
4
packages/captcha/jest.setup.js
Normal file
4
packages/captcha/jest.setup.js
Normal file
@ -0,0 +1,4 @@
|
||||
if (!process.env.LOG) {
|
||||
process.env.LOG = 'sql:warn'
|
||||
}
|
||||
process.chdir(__dirname)
|
||||
15
packages/captcha/package.json
Normal file
15
packages/captcha/package.json
Normal 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"
|
||||
}
|
||||
84
packages/captcha/src/audio.ts
Normal file
84
packages/captcha/src/audio.ts
Normal 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 })
|
||||
}
|
||||
})
|
||||
}
|
||||
10
packages/captcha/src/image.ts
Normal file
10
packages/captcha/src/image.ts
Normal 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)
|
||||
}
|
||||
1
packages/captcha/src/index.ts
Normal file
1
packages/captcha/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './image'
|
||||
8
packages/captcha/tsconfig.esm.json
Normal file
8
packages/captcha/tsconfig.esm.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "esm"
|
||||
},
|
||||
"references": [
|
||||
]
|
||||
}
|
||||
9
packages/captcha/tsconfig.json
Normal file
9
packages/captcha/tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig.common.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "lib",
|
||||
"rootDir": "src"
|
||||
},
|
||||
"references": [
|
||||
]
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user