Update test framework: fix run_tests.py to support all test files, add auto-import-check for test files

This commit is contained in:
qiaoxinjiu
2026-05-09 15:11:30 +08:00
parent eb053a347f
commit eaba8328da
21739 changed files with 2236758 additions and 719 deletions

5
node_modules/digest-fetch/.babelrc generated vendored Normal file
View File

@@ -0,0 +1,5 @@
{
"presets": [
"@babel/preset-env"
]
}

11
node_modules/digest-fetch/.eslintrc generated vendored Normal file
View File

@@ -0,0 +1,11 @@
{
"env": {
"node": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 2017
},
"rules": {
}
}

4
node_modules/digest-fetch/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,4 @@
!.gitignore
node_modules
packing

25
node_modules/digest-fetch/.travis.yml generated vendored Normal file
View File

@@ -0,0 +1,25 @@
language: node_js
node_js:
- node
- lts/*
sudo: false
cache:
directories:
- node_modules
before_install:
# Skip updating shrinkwrap / lock
- "npm config set shrinkwrap false"
# Setup Node.js version-specific dependencies
# - "test $TRAVIS_NODE_VERSION != '0.8' || npm rm --save-dev istanbul"
# - "test $(echo $TRAVIS_NODE_VERSION | cut -d. -f1) -ge 4 || npm rm --save-dev eslint eslint-plugin-markdown"
# Update Node.js modules
- "test ! -d node_modules || npm prune"
- "test ! -d node_modules || npm rebuild"
script:
# Run test script, depending on istanbul install
- "test ! -z $(npm -ps ls istanbul) || npm test"
- "test -z $(npm -ps ls istanbul) || npm run-script test-travis"
# - "test -z $(npm -ps ls eslint) || npm run-script lint"
after_script:
- "test -e ./coverage/lcov.info && npm install coveralls@2 && cat ./coverage/lcov.info | coveralls"

21
node_modules/digest-fetch/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018 Stefan Liu
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

109
node_modules/digest-fetch/README.md generated vendored Normal file
View File

@@ -0,0 +1,109 @@
# digest-fetch
[![Join the chat at https://gitter.im/devfans/digest-fetch](https://badges.gitter.im/devfans/digest-fetch.svg)](https://gitter.im/devfans/digest-fetch?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
[![Build Status][travis-image]][travis-url]
[![Test Coverage][coveralls-image]][coveralls-url]
digest auth request plugin for fetch/node-fetch also supports http basic authentication
## Installation
```
// dependencies for node
npm install node-fetch
// for browers, if to use it directly, please indcude file `digest-fetch.js` in a <script/>
<script type="application/javascript" src="path-to-digest-fetch.js'></script>
```
## Get Started
```
// Use require
const DigestFetch = require('digest-fetch')
// Use import
import * as DigestFetch from "digest-fetch"
// In browser
const DigestFetch = window.DigestFetch;
```
#### Http Basic Authentication
Create a client using basic authentication challenge
```
const client = new DigestFetch('user', 'password', { basic: true })
client.fetch(url, options).then(res => res.json).then(console.dir)
```
#### Digest Access Authentication
Create a digest authentication request client with default options
```
const client = new DigestFetch('user', 'password')
```
Specify options for digest authentication
```
const client = new DigestFetch('user', 'password', { algorithm: 'MD5' })
```
Options fields:
| field | type | default | description |
| :------------- | :---------- | :-----------: | :---------- |
| algorithm | string | 'MD5' | algorithm to be used: 'MD5' or 'MD5-sess' |
| statusCode | number | 401 | custom alternate authentication failure code for avoiding browser prompt, see details below |
| cnonceSize | number | 32 | length of the cnonce |
| logger | object | none | logger for debug, can use `console`, default no logging |
| basic | bool | false | switch to use basic authentication |
| precomputeHash | bool | false | wether to attach hash of credentials to the client instance instead of raw credential |
Details:
+ When using digest authentication in browsers, may encounter prompt window in foreground. Check: https://stackoverflow.com/questions/9859627/how-to-prevent-browser-to-invoke-basic-auth-popup-and-handle-401-error-using-jqu
Do request same way as fetch or node-fetch
```
const url = ''
const options = {}
client.fetch(url, options)
.then(resp=>resp.json())
.then(data=>console.log(data))
.catch(e=>console.error(e))
```
Pass in refresh request options factory function for conditions options needs be refreshed when trying again.
For example when posting with file stream:
```
const factory = () => ({ method: 'post', body: fs.createReadStream('path-to-file') })
client.fetch(url, {factory})
.then(resp=>resp.json())
.then(data=>console.log(data))
.catch(e=>console.error(e))
```
## About
Digest authentication: https://en.wikipedia.org/wiki/Digest_access_authentication
This plugin is implemented following RFC2069 and RFC2617, supports http basic authentication as well!
Please open issues if you find bugs or meet problems during using this plugin.
Feel free to open PRs whenever you have better ideas on this project!
[npm-image]: https://img.shields.io/npm/v/digest-fetch.svg
[npm-url]: https://npmjs.org/package/digest-fetch
[travis-image]: https://img.shields.io/travis/devfans/digest-fetch/master.svg
[travis-url]: https://travis-ci.org/devfans/digest-fetch
[coveralls-image]: https://img.shields.io/coveralls/devfans/digest-fetch/master.svg
[coveralls-url]: https://coveralls.io/r/devfans/digest-fetch?branch=master
[downloads-image]: https://img.shields.io/npm/dm/digest-fetch.svg
[downloads-url]: https://npmjs.org/package/digest-fetch

195
node_modules/digest-fetch/digest-fetch-src.js generated vendored Normal file
View File

@@ -0,0 +1,195 @@
/// !-----------------------------------------------------------------------------------------------------------
/// |
// | `digest-fetch` is a wrapper of `node-fetch` or `fetch` to provide http digest authentication boostraping.
// |
/// !-----------------------------------------------------------------------------------------------------------
const canRequire = typeof(require) == 'function'
if (typeof(fetch) !== 'function' && canRequire) var fetch = require('node-fetch')
const md5 = require('md5')
const base64 = require('base-64')
const supported_algorithms = ['MD5', 'MD5-sess']
const parse = (raw, field, trim=true) => {
const regex = new RegExp(`${field}=("[^"]*"|[^,]*)`, "i")
const match = regex.exec(raw)
if (match)
return trim ? match[1].replace(/[\s"]/g, '') : match[1]
return null
}
class DigestClient {
constructor(user, password, options={}) {
this.user = user
this.password = password
this.nonceRaw = 'abcdef0123456789'
this.logger = options.logger
this.precomputedHash = options.precomputedHash
let algorithm = options.algorithm || 'MD5'
if (!supported_algorithms.includes(algorithm)) {
if (this.logger) this.logger.warn(`Unsupported algorithm ${algorithm}, will try with MD5`)
algorithm = 'MD5'
}
this.digest = { nc: 0, algorithm, realm: '' }
this.hasAuth = false
const _cnonceSize = parseInt(options.cnonceSize)
this.cnonceSize = isNaN(_cnonceSize) ? 32 : _cnonceSize // cnonce length 32 as default
// Custom authentication failure code for avoiding browser prompt:
// https://stackoverflow.com/questions/9859627/how-to-prevent-browser-to-invoke-basic-auth-popup-and-handle-401-error-using-jqu
this.statusCode = options.statusCode
this.basic = options.basic || false
}
async fetch (url, options={}) {
if (this.basic) return fetch(url, this.addBasicAuth(options))
const resp = await fetch(url, this.addAuth(url, options))
if (resp.status == 401 || (resp.status == this.statusCode && this.statusCode)) {
this.hasAuth = false
await this.parseAuth(resp.headers.get('www-authenticate'))
if (this.hasAuth) {
const respFinal = await fetch(url, this.addAuth(url, options))
if (respFinal.status == 401 || respFinal.status == this.statusCode) {
this.hasAuth = false
} else {
this.digest.nc++
}
return respFinal
}
} else this.digest.nc++
return resp
}
addBasicAuth (options={}) {
let _options = {}
if (typeof(options.factory) == 'function') {
_options = options.factory()
} else {
_options = options
}
const auth = 'Basic ' + base64.encode(this.user + ":" + this.password)
_options.headers = _options.headers || {}
_options.headers.Authorization = auth;
if (typeof(_options.headers.set) == 'function') {
_options.headers.set('Authorization', auth)
}
if (this.logger) this.logger.debug(options)
return _options
}
static computeHash(user, realm, password) {
return md5(`${user}:${realm}:${password}`);
}
addAuth (url, options) {
if (typeof(options.factory) == 'function') options = options.factory()
if (!this.hasAuth) return options
if (this.logger) this.logger.info(`requesting with auth carried`)
const isRequest = typeof(url) === 'object' && typeof(url.url) === 'string'
const urlStr = isRequest ? url.url : url
const _url = urlStr.replace('//', '')
const uri = _url.indexOf('/') == -1 ? '/' : _url.slice(_url.indexOf('/'))
const method = options.method ? options.method.toUpperCase() : 'GET'
let ha1 = this.precomputedHash ? this.password : DigestClient.computeHash(this.user, this.digest.realm, this.password)
if (this.digest.algorithm === 'MD5-sess') {
ha1 = md5(`${ha1}:${this.digest.nonce}:${this.digest.cnonce}`);
}
// optional MD5(entityBody) for 'auth-int'
let _ha2 = ''
if (this.digest.qop === 'auth-int') {
// not implemented for auth-int
if (this.logger) this.logger.warn('Sorry, auth-int is not implemented in this plugin')
// const entityBody = xxx
// _ha2 = ':' + md5(entityBody)
}
const ha2 = md5(`${method}:${uri}${_ha2}`);
const ncString = ('00000000'+this.digest.nc).slice(-8)
let _response = `${ha1}:${this.digest.nonce}:${ncString}:${this.digest.cnonce}:${this.digest.qop}:${ha2}`
if (!this.digest.qop) _response = `${ha1}:${this.digest.nonce}:${ha2}`
const response = md5(_response);
const opaqueString = this.digest.opaque !== null ? `opaque="${this.digest.opaque}",` : ''
const qopString = this.digest.qop ? `qop="${this.digest.qop}",` : ''
const digest = `${this.digest.scheme} username="${this.user}",realm="${this.digest.realm}",\
nonce="${this.digest.nonce}",uri="${uri}",${opaqueString}${qopString}\
algorithm="${this.digest.algorithm}",response="${response}",nc=${ncString},cnonce="${this.digest.cnonce}"`
options.headers = options.headers || {}
options.headers.Authorization = digest
if (typeof(options.headers.set) == 'function') {
options.headers.set('Authorization', digest)
}
if (this.logger) this.logger.debug(options)
// const {factory, ..._options} = options
const _options = {}
Object.assign(_options, options)
delete _options.factory
return _options;
}
async parseAuth (h) {
this.lastAuth = h
if (!h || h.length < 5) {
this.hasAuth = false
return
}
this.hasAuth = true
this.digest.scheme = h.split(/\s/)[0]
this.digest.realm = (parse(h, 'realm', false) || '').replace(/["]/g, '')
this.digest.qop = this.parseQop(h)
this.digest.opaque = parse(h, 'opaque')
this.digest.nonce = parse(h, 'nonce') || ''
this.digest.cnonce = this.makeNonce()
this.digest.nc++
}
parseQop (rawAuth) {
// Following https://en.wikipedia.org/wiki/Digest_access_authentication
// to parse valid qop
// Samples
// : qop="auth,auth-init",realm=
// : qop=auth,realm=
const _qop = parse(rawAuth, 'qop')
if (_qop !== null) {
const qops = _qop.split(',')
if (qops.includes('auth')) return 'auth'
else if (qops.includes('auth-int')) return 'auth-int'
}
// when not specified
return null
}
makeNonce () {
let uid = ''
for (let i = 0; i < this.cnonceSize; ++i) {
uid += this.nonceRaw[Math.floor(Math.random() * this.nonceRaw.length)];
}
return uid
}
static parse(...args) {
return parse(...args)
}
}
if (typeof(window) === "object") window.DigestFetch = DigestClient
module.exports = DigestClient

2
node_modules/digest-fetch/digest-fetch.js generated vendored Normal file

File diff suppressed because one or more lines are too long

52
node_modules/digest-fetch/package.json generated vendored Normal file
View File

@@ -0,0 +1,52 @@
{
"name": "digest-fetch",
"version": "1.3.0",
"description": "digest auth request plugin for fetch/node-fetch also support http basic auth authentication",
"main": "digest-fetch-src.js",
"scripts": {
"lint": "eslint --plugin markdown --ext js,md .",
"test": "mocha --check-leaks --bail --no-exit --reporter spec test/digest-*",
"test-cov": "istanbul cover node_modules/mocha/bin/_mocha -- --check-leaks --no-exit --reporter dot test/",
"test-travis": "istanbul cover node_modules/mocha/bin/_mocha --report lcovonly -- --check-leaks --no-exit --reporter spec test/",
"build": "NODE_ENV=\"production\" webpack"
},
"keywords": [
"digest",
"auth",
"fetch",
"node-fetch",
"http",
"basic",
"authentication"
],
"author": "stefanliu@outlook.com",
"license": "ISC",
"repository": {
"type": "git",
"url": "git+https://github.com/devfans/digest-fetch.git"
},
"devDependencies": {
"@babel/core": "^7.14.3",
"@babel/preset-env": "^7.14.2",
"after": "^0.8.2",
"babel-loader": "^8.2.2",
"babel-polyfill": "^6.26.0",
"chai": "^4.2.0",
"chai-http": "^4.3.0",
"eslint": "^7.26.0",
"express": "^4.17.1",
"istanbul": "^1.1.0-alpha.1",
"mocha": "^8.1.1",
"node-fetch": "^2.6.7",
"passport": "^0.6.0",
"passport-http": "^0.3.0",
"serialize-javascript": "^3.1.0",
"webpack": "^5.67.0",
"webpack-cli": "^4.9.1"
},
"homepage": "https://github.com/devfans/digest-fetch#readme",
"dependencies": {
"base-64": "^0.1.0",
"md5": "^2.3.0"
}
}

30
node_modules/digest-fetch/test/digest-fetch-basic.js generated vendored Normal file
View File

@@ -0,0 +1,30 @@
process.env.NO_DEPRECATION = 'digest-fetch';
var after = require('after')
var assert = require('assert')
var DigestFetch = require('../')
var factory = require('./test-server')
var chai = require('chai')
var expect = chai.expect
var chaiHttp = require('chai-http')
chai.use(chaiHttp)
chai.should()
var app = factory.getApp()
describe('digest-fetch', function(){
it('Test Basic Authentication', function() {
var client = new DigestFetch('test', 'test', { basic: true })
const auth = client.addBasicAuth().headers.Authorization
chai.request(app).get('/basic').set('Authorization', auth).then(res => {
expect(res).to.have.status(200)
})
})
it('Test Basic Authentication with wrong credential', function() {
var client = new DigestFetch('test', 'test-null', { basic: true })
const auth = client.addBasicAuth().headers.Authorization
chai.request(app).get('/basic').set('Authorization', auth).then(res => {
expect(res).to.have.status(401)
})
})
})

45
node_modules/digest-fetch/test/digest-fetch-rfc2069.js generated vendored Normal file
View File

@@ -0,0 +1,45 @@
process.env.NO_DEPRECATION = 'digest-fetch';
var after = require('after')
var assert = require('assert')
var DigestFetch = require('../')
var factory = require('./test-server')
var chai = require('chai')
var expect = chai.expect
var chaiHttp = require('chai-http')
chai.use(chaiHttp)
chai.should()
var app = factory.getApp()
describe('digest-fetch', function(){
it('Test RFC2069', function() {
var client = new DigestFetch('test', 'test')
chai.request(app).get('/auth').then(res => {
expect(res).to.have.status(401)
client.lastAuth = res.res.headers['www-authenticate']
})
.then(() => {
client.parseAuth(client.lastAuth)
const auth = client.addAuth('/auth', { method: 'GET' }).headers.Authorization
chai.request(app).get('/auth').set('Authorization', auth).then(res => {
expect(res).to.have.status(200)
})
})
})
it('Test RFC2069 with wrong credential', function() {
var client = new DigestFetch('test', 'test-null')
chai.request(app).get('/auth').then(res => {
res.should.have.status(401)
client.lastAuth = res.res.headers['www-authenticate']
})
.then(() => {
client.parseAuth(client.lastAuth)
const auth = client.addAuth('/auth', { method: 'GET' }).headers.Authorization
chai.request(app).get('/auth').set('Authorization', auth).then(res => {
expect(res).to.have.status(401)
})
})
})
})

60
node_modules/digest-fetch/test/digest-fetch-rfc2617.js generated vendored Normal file
View File

@@ -0,0 +1,60 @@
process.env.NO_DEPRECATION = 'digest-fetch';
var after = require('after')
var assert = require('assert')
var DigestFetch = require('../')
var factory = require('./test-server')
var chai = require('chai')
var expect = chai.expect
var chaiHttp = require('chai-http')
chai.use(chaiHttp)
chai.should()
var app = factory.getApp('auth')
describe('digest-fetch', function(){
it('Test RFC2617', function() {
var client = new DigestFetch('test', 'test')
chai.request(app).get('/auth').then(res => {
expect(res).to.have.status(401)
client.lastAuth = res.res.headers['www-authenticate']
})
.then(() => {
client.parseAuth(client.lastAuth)
const auth = client.addAuth('/auth', { method: 'GET' }).headers.Authorization
chai.request(app).get('/auth').set('Authorization', auth).then(res => {
expect(res).to.have.status(200)
})
})
})
it('Test RFC2617 with precomputed hash', function() {
var client = new DigestFetch('test', DigestFetch.computeHash('test', 'Users', 'test'), { precomputedHash: true })
chai.request(app).get('/auth').then(res => {
expect(res).to.have.status(401)
client.lastAuth = res.res.headers['www-authenticate']
})
.then(() => {
client.parseAuth(client.lastAuth)
const auth = client.addAuth('/auth', { method: 'GET' }).headers.Authorization
chai.request(app).get('/auth').set('Authorization', auth).then(res => {
expect(res).to.have.status(200)
})
})
})
it('Test RFC2617 with wrong credential', function() {
var client = new DigestFetch('test', 'test-null')
chai.request(app).get('/auth').then(res => {
expect(res).to.have.status(401)
client.lastAuth = res.res.headers['www-authenticate']
})
.then(() => {
client.parseAuth(client.lastAuth)
const auth = client.addAuth('/auth', { method: 'GET' }).headers.Authorization
chai.request(app).get('/auth').set('Authorization', auth).then(res => {
expect(res).to.have.status(401)
})
})
})
})

40
node_modules/digest-fetch/test/digest-fetch.js generated vendored Normal file
View File

@@ -0,0 +1,40 @@
process.env.NO_DEPRECATION = 'digest-fetch';
var after = require('after')
var assert = require('assert')
var DigestFetch = require('../')
describe('digest-fetch', function(){
it('get function', function(){
assert.equal(typeof DigestFetch, 'function')
})
it('should success', function() {
var client = new DigestFetch('test', '123')
assert.equal(typeof client.fetch, 'function')
client.parseAuth('')
client.addAuth('', {headers: {}})
assert.equal(client.digest.nc, 0)
})
it('test parse string fields', function () {
assert.equal(DigestFetch.parse('a=,', 'a'), '')
assert.equal(DigestFetch.parse('a=v1,', 'a'), 'v1')
assert.equal(DigestFetch.parse('a=""', 'b'), null)
assert.equal(DigestFetch.parse('a="v2",', 'a'), 'v2')
assert.equal(DigestFetch.parse('a="v1,v2"', 'a'), 'v1,v2')
const client = new DigestFetch("", "")
client.parseAuth('qop=auth-int,realm=test')
assert.equal(client.digest.realm, "test")
client.parseAuth('qop="auth",realm="v1 v2"')
assert.equal(client.digest.realm, "v1 v2")
})
it('test qop parsing', function () {
var client = new DigestFetch('test', '123')
assert.equal(client.parseQop('qop=auth,realm='), 'auth')
assert.equal(client.parseQop('qop="auth",realm='), 'auth')
assert.equal(client.parseQop('qop="auth,auth-int",realm='), 'auth')
assert.equal(client.parseQop('qop="auth-int",realm='), 'auth-int')
})
})

62
node_modules/digest-fetch/test/test-server.js generated vendored Normal file
View File

@@ -0,0 +1,62 @@
const path = require("path");
const express = require("express");
const passport = require('passport');
const Strategies = require("passport-http");
const DigestStrategy = Strategies.DigestStrategy;
const BasicStrategy = Strategies.BasicStrategy;
module.exports = { getApp(method) {
const app = express();
const User = {
findOne(user, callback) {
return callback(null, { password: "test", username: user.username });
}
}
passport.use(new BasicStrategy(
function(userid, password, done) {
User.findOne({ username: userid }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
if (user.password != password) { return done(null, false); }
return done(null, user);
});
}
));
const options = {}
if (method) options.qop = method
passport.use(new DigestStrategy(options,
function(username, done) {
User.findOne({ username: username }, function (err, user) {
if (err) { return done(err); }
if (!user) { return done(null, false); }
return done(null, user, user.password);
});
},
function(params, done) {
// validate nonces as necessary
done(null, true)
}
));
// http basic authentication
app.get('/basic',
passport.authenticate('basic', { session: false }),
function(req, res) {
res.json(req.user);
});
// http digest authentication
app.get('/auth',
passport.authenticate('digest', { session: false }),
function(req, res) {
res.json(req.user);
});
// app.use("/static", express.static(path.join(__dirname, './static')));
// app.get('/', (req, res) => res.sendFile("/home/stefan/digest/main.html") );
// app.listen(3222, "0.0.0.0");
return app
}}

39
node_modules/digest-fetch/webpack.config.js generated vendored Normal file
View File

@@ -0,0 +1,39 @@
require("babel-polyfill");
const webpack = require('webpack')
const path = require('path')
module.exports = {
mode: 'production',
target: "web",
context: path.join(__dirname, './digest-fetch-src.js'),
entry: [
"babel-polyfill",
path.join(__dirname, './digest-fetch-src.js')
],
output: {
uniqueName: 'digest-fetch.js',
path: path.join(__dirname, '.'),
filename: 'digest-fetch.js',
globalObject: 'this'
},
module: {
rules: [
{
test : /\.js$/,
exclude : /(node_modules|build|dist\/)/,
loader : 'babel-loader',
options : { presets: ["@babel/preset-env"] }
}
]
},
resolve: {
extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js'],
modules: [
path.join(__dirname, './node_modules'),
__dirname,
],
},
optimization: {
minimize: true,
},
};