File size: 4,179 Bytes
1b5ed97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import express from 'express'
import template from 'express-art-template'
import http from 'http'
import lodash from 'lodash'
import fs from 'node:fs'
import { resolve } from 'node:path'
import YAML from 'yaml'

class example {
  constructor () {
    this.cfg = YAML.parse(fs.readFileSync('./config.yaml', 'utf8'))
    this.tmp = {}
    this.isRegister = {}
    this.result = {}
    this.load(express())
    console.log(`Successfully started, port: \x1b[32m${this.cfg.Port}\x1b[0m`)
    console.log('\x1b[32m%s\x1b[0m', `[POST] ${this.address}/register${this.cfg.Key && `?key=${this.cfg.Key}`}`)//`
  }

  load(app) {
    // 使用服务器自带的 HTTP 配置
    http.createServer(app).listen(this.cfg.Port);
    this.route(app);
  }

  route (app) {
    app.use(express.static(resolve('public')))
    app.use(express.urlencoded({ extended: false }))
    app.use(express.json())
    app.engine('html', template)
    app.set('views', resolve('public'))
    app.set('view engine', 'html')
    app.get('/GTest/:key', this.self('index'))
    app.post('/GTest/register', this.self('register'))
    app.get('/GTest/register/:key', this.self('get_register'))
    app.post('/GTest/validate/:key', this.self('validate'))
    app.get('/GTest/validate/:key', this.self('get_validate'))
    app.use(this.invalid)
    app.use(this.error)
  }

  /** 模板引擎为常用的art-template */
  index (req, res, next) {
    let { key } = req.params
    if (!key || !this.isRegister[key]) return next('验证信息不存在或已失效。')
    res.render('GTest/main', { key, copyright: this.cfg.Copyright })
  }

  /** 验证信息, post传mys接口res.data */
  register (req, res, next) {
    let { key } = req.query, { gt, challenge } = req.body || {}
    if (!gt || !challenge) return next('error')
    if (this.cfg.Key && key !== this.cfg.Key) return next('please enter the correct key')
    for (let i = 0; i < 99; i++) {
      key = lodash.sampleSize('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 6).join('')
      if (this.isRegister[key] || this.result[key]) continue
      break
    }
    this.tmp[key] = req.body
    this.isRegister[key] = 1
    /** 未点击2分钟后删除 */
    setTimeout(() => delete this.tmp[key] && delete this.isRegister[key], 120000)
    this.send(res, {
      link: `${this.address}/${key}`,
      result: `${this.address}/validate/${key}`
    })
  }

  /** 浏览器获取gt参数 */
  get_register (req, res, next) {
    let { key } = req.params
    if (!key || !this.tmp[key]) return next('该验证信息已被使用,若非本人操作请重新获取')
    res.send(this.tmp[key] || {})
    delete this.tmp[key]
  }

  /** 浏览器返回validate */
  validate (req, res, next) {
    let { key } = req.params
    if (!key || !req.body) return next('error')
    this.result[key] = req.body
    setTimeout(() => delete this.result[key], 30000)
    this.send(res, {})
    delete this.isRegister[key]
    console.log('[GeeTest] 验证成功, key:', key)
  }

  /** 获取验证结果validate,改为挂起 */
  async get_validate (req, res, next) {
    let { key } = req.params, data = null
    if (!key) return next('error')

    if (this.isRegister[key] || this.result[key]) {
      for (let i = 0; i < 120; i++) {
        if (this.result[key]) {
          data = this.result[key]
          break
        }
        await new Promise((resolve) => setTimeout(resolve, 1000))
      }
      if (!data) data = {}
    }
    this.send(res, data)
  }

  invalid (req, res) {
    if (!res.finished) res.status(404).end()
  }

  error (err, req, res, next) {
    let message = err?.message || (err !== 'error' && `${err}`) || 'Invalid request'
    if (!res.finished) res.send({ status: 1, message })
  }

  send (res, data, message = 'OK') {
    res.send({
      status: Number(!data),
      message,
      data
    })
  }

  get address () {
    let { Host, Port, Https, Key } = this.cfg
    if (![80, 443,7860].includes(Port)) Host += `:${Port}`
    return `https://${Host}/GTest`
  }

  self (fn) {
    return (...args) => this[fn].call(this, ...args)
  }
}

process.on('unhandledRejection', (error, promise) => console.log(error))
new example()