@mattduffy/banner 1.2.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Readme.md +24 -17
- package/package.json +1 -1
- package/src/index.js +78 -14
- package/test/test.js +47 -26
package/Readme.md
CHANGED
|
@@ -30,9 +30,11 @@ app.use(banner.use())
|
|
|
30
30
|
/*
|
|
31
31
|
Emits at the beginning of each client request.
|
|
32
32
|
#################################################################
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
33
|
+
# GET: https://dev.example.com/map/getToken
|
|
34
|
+
# Query Params: ?debug=verbose
|
|
35
|
+
# Referer: https://dev.example.com/?debug=verbose
|
|
36
|
+
# From IP: 192.168.1.254
|
|
37
|
+
# Timestamp: 1/7/2026, 10:34:14 AM
|
|
36
38
|
#################################################################
|
|
37
39
|
*/
|
|
38
40
|
```
|
|
@@ -43,36 +45,41 @@ the ```ctx.request.method``` property. The supported request methods are ```GET
|
|
|
43
45
|
|
|
44
46
|
```
|
|
45
47
|
// GET
|
|
46
|
-
|
|
47
|
-
#
|
|
48
|
-
#
|
|
49
|
-
#
|
|
50
|
-
|
|
48
|
+
##########################################################################
|
|
49
|
+
# GET: https://banner.test/a/really/long/url/to/a/special/page
|
|
50
|
+
# Query Params: ?param1=querty¶m2=12345¶m3=true
|
|
51
|
+
# Referer: https://googoogle.com
|
|
52
|
+
# From IP: 192.168.1.250
|
|
53
|
+
# Timestamp: 1/7/2026, 10:34:14 AM
|
|
54
|
+
##########################################################################
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
```
|
|
54
58
|
// PUT
|
|
55
59
|
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
|
|
56
|
-
&
|
|
57
|
-
&
|
|
58
|
-
&
|
|
60
|
+
& PUT: https://banner.test/a/really/long/url/to/a/special/page
|
|
61
|
+
& Referer: https://googoogle.com
|
|
62
|
+
& From IP: 192.168.1.250
|
|
63
|
+
& Timestamp: 1/7/2026, 10:34:14 AM
|
|
59
64
|
&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
|
|
60
65
|
```
|
|
61
66
|
|
|
62
67
|
```
|
|
63
68
|
// POST
|
|
64
69
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
65
|
-
@
|
|
66
|
-
@
|
|
67
|
-
@
|
|
70
|
+
@ POST: https://banner.test/a/really/long/url/to/a/special/page
|
|
71
|
+
@ Referer: https://googoogle.com
|
|
72
|
+
@ From IP: 192.168.1.250
|
|
73
|
+
@ Timestamp: 1/7/2026, 10:34:14 AM
|
|
68
74
|
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
|
|
69
75
|
```
|
|
70
76
|
|
|
71
77
|
```
|
|
72
78
|
// DELETE
|
|
73
79
|
**********************************************************************
|
|
74
|
-
*
|
|
75
|
-
*
|
|
76
|
-
*
|
|
80
|
+
* DELETE: https://banner.test/a/really/long/url/to/a/special/page
|
|
81
|
+
* Referer: https://googoogle.com
|
|
82
|
+
* From IP: 192.168.1.250
|
|
83
|
+
* Timestamp: 1/7/2026, 10:34:14 AM
|
|
77
84
|
**********************************************************************
|
|
78
85
|
```
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -295,6 +295,7 @@ export class Banner {
|
|
|
295
295
|
break
|
|
296
296
|
case 'post':
|
|
297
297
|
_g = gPOST
|
|
298
|
+
console.info(ctx.request.body)
|
|
298
299
|
break
|
|
299
300
|
case 'put':
|
|
300
301
|
_g = gPUT
|
|
@@ -317,21 +318,66 @@ export class Banner {
|
|
|
317
318
|
if (!ctx.request.url) {
|
|
318
319
|
throw new Error('Missing required request url value.')
|
|
319
320
|
}
|
|
321
|
+
const labels = []
|
|
322
|
+
const values = []
|
|
323
|
+
const lines = []
|
|
320
324
|
const _urlLabel = `${ctx.request.method}:`
|
|
321
|
-
|
|
325
|
+
let _url = `${ctx.request.protocol}://${ctx.request.header.host}${ctx.request.url}`
|
|
326
|
+
const _queryStringIndex = _url.indexOf('?')
|
|
327
|
+
const _queryStringLabel = 'Query Params:'
|
|
328
|
+
let _queryString = ''
|
|
329
|
+
let _queryStringLine = ''
|
|
330
|
+
if (_queryStringIndex !== -1) {
|
|
331
|
+
_queryString = _url.slice(_url.indexOf('?'))
|
|
332
|
+
_queryStringLine = `${_queryStringLabel} ${_queryString}`
|
|
333
|
+
labels.push(_queryStringLabel)
|
|
334
|
+
values.push(_queryString)
|
|
335
|
+
lines.push(_queryStringLine)
|
|
336
|
+
// console.log('adding query string to request banner')
|
|
337
|
+
}
|
|
338
|
+
_url = (_queryString.length > 0) ? _url.slice(0, _url.indexOf('?')) : _url
|
|
339
|
+
values.push(_url)
|
|
322
340
|
let _urlLine = `${_urlLabel} ${_url}`
|
|
323
341
|
const _refLabel = 'Referer:'
|
|
324
342
|
const _ref = ctx.request.header.referer ?? '<emtpy header field>'
|
|
343
|
+
values.push(_ref)
|
|
325
344
|
let _refLine = `${_refLabel} ${_ref}`
|
|
326
345
|
const _ipLabel = 'From IP:'
|
|
327
346
|
const _ip = ctx.request.ip
|
|
347
|
+
values.push(_ip)
|
|
328
348
|
let _ipLine = `${_ipLabel} ${_ip}`
|
|
329
|
-
const
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
349
|
+
const _timestampLabel = 'Timestamp:'
|
|
350
|
+
const _timestamp = new Date().toLocaleString()
|
|
351
|
+
values.push(_timestamp)
|
|
352
|
+
let _timestampLine = `${_timestampLabel} ${_timestamp}`
|
|
353
|
+
labels.push(_urlLabel)
|
|
354
|
+
labels.push(_refLabel)
|
|
355
|
+
labels.push(_ipLabel)
|
|
356
|
+
labels.push(_timestampLabel)
|
|
357
|
+
// console.log(labels)
|
|
358
|
+
|
|
359
|
+
// console.log(values)
|
|
360
|
+
const _longestValue = values
|
|
361
|
+
.reduce((a, c) => {
|
|
362
|
+
if (a > c.length) return a
|
|
363
|
+
return c.length
|
|
364
|
+
}, '')
|
|
365
|
+
// console.log('longest value', _longestValue)
|
|
366
|
+
|
|
367
|
+
lines.push(_ipLine)
|
|
368
|
+
lines.push(_timestampLine)
|
|
369
|
+
lines.push(_urlLine)
|
|
370
|
+
lines.push(_refLine)
|
|
371
|
+
// console.log(lines)
|
|
372
|
+
const _longestLabel = labels
|
|
373
|
+
.reduce((a, c) => {
|
|
374
|
+
// console.log(a, c.indexOf(':') + 1)
|
|
375
|
+
if (a > (c.indexOf(':') + 1)) {
|
|
376
|
+
return a
|
|
377
|
+
}
|
|
378
|
+
return (c.indexOf(':') + 1)
|
|
379
|
+
}, '')
|
|
380
|
+
// console.log('longest label', _longestLabel)
|
|
335
381
|
_refLine = _refLine.padStart(
|
|
336
382
|
(_longestLabel - _refLine.indexOf(':')) + _refLine.length,
|
|
337
383
|
' ',
|
|
@@ -340,20 +386,38 @@ export class Banner {
|
|
|
340
386
|
(_longestLabel - _urlLine.indexOf(':')) + _urlLine.length,
|
|
341
387
|
' ',
|
|
342
388
|
)
|
|
389
|
+
if (_queryStringLine.length > 0) {
|
|
390
|
+
_queryStringLine = _queryStringLine.padStart(
|
|
391
|
+
(_longestLabel - _queryStringLine.indexOf(':')) + _queryStringLine.length,
|
|
392
|
+
' ',
|
|
393
|
+
)
|
|
394
|
+
}
|
|
343
395
|
_ipLine = _ipLine.padStart(
|
|
344
396
|
(_longestLabel - _ipLine.indexOf(':')) + _ipLine.length,
|
|
345
397
|
' ',
|
|
346
398
|
)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
399
|
+
_timestampLine = _timestampLine.padStart(
|
|
400
|
+
(_longestLabel - _timestampLine.indexOf(':')) + _timestampLine.length,
|
|
401
|
+
' ',
|
|
402
|
+
)
|
|
403
|
+
const _longestLine = _longestLabel + _longestValue
|
|
404
|
+
// const _longestLine = lines
|
|
405
|
+
// .reduce((a, c) => {
|
|
406
|
+
// // console.log(a, c.length)
|
|
407
|
+
// if (a > c.length) return a
|
|
408
|
+
// return c.length
|
|
409
|
+
// }, '')
|
|
410
|
+
// console.log('longest line', _longestLine)
|
|
411
|
+
/* eslint-disable prefer-template */
|
|
412
|
+
const endDangler = 6
|
|
413
|
+
_requestBanner = `${_g.padEnd(_longestLine + endDangler, _g)}\n`
|
|
353
414
|
+ `${_g} ${_urlLine}\n`
|
|
415
|
+
+ `${(_queryStringLine.length > 0) ? _g + ' ' + _queryStringLine + '\n' : ''}`
|
|
354
416
|
+ `${_g} ${_refLine}\n`
|
|
355
417
|
+ `${_g} ${_ipLine}\n`
|
|
356
|
-
+ `${_g
|
|
418
|
+
+ `${_g} ${_timestampLine}\n`
|
|
419
|
+
+ `${_g.padEnd(_longestLine + endDangler, _g)}`
|
|
420
|
+
/* eslint-enable prefer-template */
|
|
357
421
|
_log(_requestBanner)
|
|
358
422
|
if (next) {
|
|
359
423
|
await next(ctx.request.method)
|
package/test/test.js
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
// import path from 'node:path'
|
|
2
2
|
// import { randomBytes } from 'node:crypto'
|
|
3
3
|
import {
|
|
4
|
-
after,
|
|
4
|
+
// after,
|
|
5
5
|
before,
|
|
6
6
|
describe,
|
|
7
7
|
it,
|
|
8
8
|
} from 'node:test'
|
|
9
9
|
import assert from 'node:assert/strict'
|
|
10
|
-
import fs from 'node:fs/promises'
|
|
10
|
+
// import fs from 'node:fs/promises'
|
|
11
11
|
import os from 'node:os'
|
|
12
12
|
import { Banner } from '../src/index.js'
|
|
13
|
+
|
|
14
|
+
/* eslint-disable camelcase */
|
|
13
15
|
const skip = { skip: true }
|
|
14
16
|
console.log(skip)
|
|
15
17
|
let cfg
|
|
@@ -22,23 +24,25 @@ let next
|
|
|
22
24
|
describe('First test suite for banner package', async () => {
|
|
23
25
|
before(() => {
|
|
24
26
|
function getLocalIpAddress() {
|
|
25
|
-
const networkInterfaces = os.networkInterfaces()
|
|
26
|
-
let localIpAddress = null
|
|
27
|
-
|
|
27
|
+
const networkInterfaces = os.networkInterfaces()
|
|
28
|
+
let localIpAddress = null
|
|
29
|
+
|
|
30
|
+
/* eslint-disable no-restricted-syntax */
|
|
31
|
+
/* eslint-disable guard-for-in */
|
|
28
32
|
for (const interfaceName in networkInterfaces) {
|
|
29
|
-
const networkInterface = networkInterfaces[interfaceName]
|
|
33
|
+
const networkInterface = networkInterfaces[interfaceName]
|
|
30
34
|
for (const details of networkInterface) {
|
|
31
35
|
// Check for IPv4, not internal (loopback), and a valid address
|
|
32
36
|
if (details.family === 'IPv4' && !details.internal) {
|
|
33
|
-
localIpAddress = details.address
|
|
34
|
-
break
|
|
37
|
+
localIpAddress = details.address
|
|
38
|
+
break // Found a suitable IPv4 address, exit inner loop
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
if (localIpAddress) {
|
|
38
|
-
break
|
|
42
|
+
break // Found a suitable IPv4 address, exit outer loop
|
|
39
43
|
}
|
|
40
44
|
}
|
|
41
|
-
return localIpAddress
|
|
45
|
+
return localIpAddress
|
|
42
46
|
}
|
|
43
47
|
ctx = {
|
|
44
48
|
request: {
|
|
@@ -71,21 +75,22 @@ describe('First test suite for banner package', async () => {
|
|
|
71
75
|
})
|
|
72
76
|
|
|
73
77
|
it('Should create a start-up banner instance, with constructor param.', () => {
|
|
74
|
-
const banner = new Banner(cfg)
|
|
78
|
+
const banner = new Banner(cfg)
|
|
75
79
|
assert(banner.bannerText.length > 0)
|
|
76
80
|
assert(typeof banner.bannerText === 'string')
|
|
77
81
|
})
|
|
78
|
-
|
|
82
|
+
|
|
79
83
|
it('Should fail', () => {
|
|
80
84
|
const banner = new Banner()
|
|
81
85
|
assert(!banner.print())
|
|
82
86
|
})
|
|
83
87
|
|
|
84
88
|
it('Should work as a koajs middleware function - POST method.', async () => {
|
|
85
|
-
ctx_POST = Object.assign({}, ctx)
|
|
89
|
+
// ctx_POST = Object.assign({}, ctx)
|
|
90
|
+
ctx_POST = { ...ctx }
|
|
86
91
|
ctx_POST.request.method = 'POST'
|
|
87
|
-
ctx_POST.throw = (code, err
|
|
88
|
-
throw new Error(`${code}, ${
|
|
92
|
+
ctx_POST.throw = (code, err) => {
|
|
93
|
+
throw new Error(`${code}, ${err}`)
|
|
89
94
|
}
|
|
90
95
|
console.log(ctx_POST)
|
|
91
96
|
const post = new Banner(ctx_POST)
|
|
@@ -93,10 +98,11 @@ describe('First test suite for banner package', async () => {
|
|
|
93
98
|
})
|
|
94
99
|
|
|
95
100
|
it('Should work as a koajs middleware function - GET method.', async () => {
|
|
96
|
-
ctx_GET = Object.assign({}, ctx)
|
|
101
|
+
// ctx_GET = Object.assign({}, ctx)
|
|
102
|
+
ctx_GET = { ...ctx }
|
|
97
103
|
ctx_GET.request.method = 'GET'
|
|
98
|
-
ctx_GET.throw = (code, err
|
|
99
|
-
throw new Error(`${code}, ${
|
|
104
|
+
ctx_GET.throw = (code, err) => {
|
|
105
|
+
throw new Error(`${code}, ${err}`)
|
|
100
106
|
}
|
|
101
107
|
console.log(ctx_GET)
|
|
102
108
|
const get = new Banner(ctx_GET)
|
|
@@ -104,10 +110,11 @@ describe('First test suite for banner package', async () => {
|
|
|
104
110
|
})
|
|
105
111
|
|
|
106
112
|
it('Should work as a koajs middleware function - PUT method.', async () => {
|
|
107
|
-
ctx_PUT = Object.assign({}, ctx)
|
|
113
|
+
// ctx_PUT = Object.assign({}, ctx)
|
|
114
|
+
ctx_PUT = { ...ctx }
|
|
108
115
|
ctx_PUT.request.method = 'PUT'
|
|
109
|
-
ctx_PUT.throw = (code, err
|
|
110
|
-
throw new Error(`${code}, ${
|
|
116
|
+
ctx_PUT.throw = (code, err) => {
|
|
117
|
+
throw new Error(`${code}, ${err}`)
|
|
111
118
|
}
|
|
112
119
|
console.log(ctx_PUT)
|
|
113
120
|
const put = new Banner(ctx_PUT)
|
|
@@ -115,22 +122,36 @@ describe('First test suite for banner package', async () => {
|
|
|
115
122
|
})
|
|
116
123
|
|
|
117
124
|
it('Should work as a koajs middleware function - DELETE method.', async () => {
|
|
118
|
-
ctx_DEL = Object.assign({}, ctx)
|
|
125
|
+
// ctx_DEL = Object.assign({}, ctx)
|
|
126
|
+
ctx_DEL = { ...ctx }
|
|
119
127
|
ctx_DEL.request.method = 'DELETE'
|
|
120
|
-
ctx_DEL.throw = (code, err
|
|
121
|
-
throw new Error(`${code}, ${
|
|
128
|
+
ctx_DEL.throw = (code, err) => {
|
|
129
|
+
throw new Error(`${code}, ${err}`)
|
|
122
130
|
}
|
|
123
131
|
console.log(ctx_DEL)
|
|
124
132
|
const del = new Banner(ctx_DEL)
|
|
125
133
|
assert(await del.use()(ctx_DEL, next))
|
|
126
134
|
})
|
|
127
135
|
|
|
128
|
-
it('Should
|
|
136
|
+
it('Should work as a koajs middleware function - GET method, with query string.', async () => {
|
|
137
|
+
// ctx_GET = Object.assign({}, ctx)
|
|
138
|
+
ctx_GET = { ...ctx }
|
|
139
|
+
ctx_GET.request.method = 'GET'
|
|
140
|
+
ctx_GET.request.url += '?param1=querty¶m2=12345¶m3=true'
|
|
141
|
+
ctx_GET.throw = (code, err) => {
|
|
142
|
+
throw new Error(`${code}, ${err}`)
|
|
143
|
+
}
|
|
144
|
+
console.log(ctx_GET)
|
|
145
|
+
const get = new Banner(ctx_GET)
|
|
146
|
+
assert(await get.use()(ctx_GET, next))
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('Should fail as a koajs middleware function, missing input parameters.', async () => {
|
|
129
150
|
ctx.request.header.host = null
|
|
130
151
|
ctx.request.url = null
|
|
131
152
|
ctx.throw = (code, err) => {
|
|
132
153
|
// console.log(err.message)
|
|
133
|
-
throw err
|
|
154
|
+
throw err
|
|
134
155
|
}
|
|
135
156
|
console.log(ctx)
|
|
136
157
|
const req = new Banner()
|