adapt-authoring-middleware 0.0.1 → 1.0.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/.github/ISSUE_TEMPLATE/bug_report.yml +55 -55
- package/.github/ISSUE_TEMPLATE/feature_request.yml +22 -22
- package/.github/dependabot.yml +11 -11
- package/.github/pull_request_template.md +25 -25
- package/.github/workflows/add-to-project-label.yml +18 -18
- package/.github/workflows/new.yml +15 -19
- package/.github/workflows/releases.yml +32 -0
- package/.github/workflows/standardjs.yml +13 -0
- package/adapt-authoring.json +5 -5
- package/conf/config.schema.json +38 -38
- package/errors/errors.json +28 -28
- package/index.js +5 -5
- package/lib/MiddlewareModule.js +282 -278
- package/lib/typedefs.js +13 -13
- package/package.json +63 -29
- package/.eslintignore +0 -1
- package/.eslintrc +0 -14
- package/.github/workflows/labelled_prs.yml +0 -16
|
@@ -1,55 +1,55 @@
|
|
|
1
|
-
name: Bug Report
|
|
2
|
-
description: File a bug report
|
|
3
|
-
labels: ["bug"]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
Thanks for taking the time to fill out this bug report!
|
|
9
|
-
- type: textarea
|
|
10
|
-
id: description
|
|
11
|
-
attributes:
|
|
12
|
-
label: What happened?
|
|
13
|
-
description: Please describe the issue
|
|
14
|
-
validations:
|
|
15
|
-
required: true
|
|
16
|
-
- type: textarea
|
|
17
|
-
id: expected
|
|
18
|
-
attributes:
|
|
19
|
-
label: Expected behaviour
|
|
20
|
-
description: Tell us what should have happened
|
|
21
|
-
- type: textarea
|
|
22
|
-
id: repro-steps
|
|
23
|
-
attributes:
|
|
24
|
-
label: Steps to reproduce
|
|
25
|
-
description: Tell us how to reproduce the issue
|
|
26
|
-
validations:
|
|
27
|
-
required: true
|
|
28
|
-
- type: input
|
|
29
|
-
id: aat-version
|
|
30
|
-
attributes:
|
|
31
|
-
label: Authoring tool version
|
|
32
|
-
description: What version of the Adapt authoring tool are you running?
|
|
33
|
-
validations:
|
|
34
|
-
required: true
|
|
35
|
-
- type: input
|
|
36
|
-
id: fw-version
|
|
37
|
-
attributes:
|
|
38
|
-
label: Framework version
|
|
39
|
-
description: What version of the Adapt framework are you running?
|
|
40
|
-
- type: dropdown
|
|
41
|
-
id: browsers
|
|
42
|
-
attributes:
|
|
43
|
-
label: What browsers are you seeing the problem on?
|
|
44
|
-
multiple: true
|
|
45
|
-
options:
|
|
46
|
-
- Firefox
|
|
47
|
-
- Chrome
|
|
48
|
-
- Safari
|
|
49
|
-
- Microsoft Edge
|
|
50
|
-
- type: textarea
|
|
51
|
-
id: logs
|
|
52
|
-
attributes:
|
|
53
|
-
label: Relevant log output
|
|
54
|
-
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
|
55
|
-
render: sh
|
|
1
|
+
name: Bug Report
|
|
2
|
+
description: File a bug report
|
|
3
|
+
labels: ["bug"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to fill out this bug report!
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: description
|
|
11
|
+
attributes:
|
|
12
|
+
label: What happened?
|
|
13
|
+
description: Please describe the issue
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: textarea
|
|
17
|
+
id: expected
|
|
18
|
+
attributes:
|
|
19
|
+
label: Expected behaviour
|
|
20
|
+
description: Tell us what should have happened
|
|
21
|
+
- type: textarea
|
|
22
|
+
id: repro-steps
|
|
23
|
+
attributes:
|
|
24
|
+
label: Steps to reproduce
|
|
25
|
+
description: Tell us how to reproduce the issue
|
|
26
|
+
validations:
|
|
27
|
+
required: true
|
|
28
|
+
- type: input
|
|
29
|
+
id: aat-version
|
|
30
|
+
attributes:
|
|
31
|
+
label: Authoring tool version
|
|
32
|
+
description: What version of the Adapt authoring tool are you running?
|
|
33
|
+
validations:
|
|
34
|
+
required: true
|
|
35
|
+
- type: input
|
|
36
|
+
id: fw-version
|
|
37
|
+
attributes:
|
|
38
|
+
label: Framework version
|
|
39
|
+
description: What version of the Adapt framework are you running?
|
|
40
|
+
- type: dropdown
|
|
41
|
+
id: browsers
|
|
42
|
+
attributes:
|
|
43
|
+
label: What browsers are you seeing the problem on?
|
|
44
|
+
multiple: true
|
|
45
|
+
options:
|
|
46
|
+
- Firefox
|
|
47
|
+
- Chrome
|
|
48
|
+
- Safari
|
|
49
|
+
- Microsoft Edge
|
|
50
|
+
- type: textarea
|
|
51
|
+
id: logs
|
|
52
|
+
attributes:
|
|
53
|
+
label: Relevant log output
|
|
54
|
+
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
|
|
55
|
+
render: sh
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
name: Feature request
|
|
2
|
-
description: Request a new feature
|
|
3
|
-
labels: ["enhancement"]
|
|
4
|
-
body:
|
|
5
|
-
- type: markdown
|
|
6
|
-
attributes:
|
|
7
|
-
value: |
|
|
8
|
-
Thanks for taking the time to request a new feature in the Adapt authoring tool! The Adapt team will consider all new feature requests, but unfortunately cannot commit to every one.
|
|
9
|
-
- type: textarea
|
|
10
|
-
id: description
|
|
11
|
-
attributes:
|
|
12
|
-
label: Feature description
|
|
13
|
-
description: Please describe your feature request
|
|
14
|
-
validations:
|
|
15
|
-
required: true
|
|
16
|
-
- type: checkboxes
|
|
17
|
-
id: contribute
|
|
18
|
-
attributes:
|
|
19
|
-
label: Can you work on this feature?
|
|
20
|
-
description: If you are able to commit your own time to work on this feature, it will greatly increase the liklihood of it being implemented by the core dev team. Otherwise, it will be triaged and prioritised alongside the core team's current priorities.
|
|
21
|
-
options:
|
|
22
|
-
- label: I can contribute
|
|
1
|
+
name: Feature request
|
|
2
|
+
description: Request a new feature
|
|
3
|
+
labels: ["enhancement"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
Thanks for taking the time to request a new feature in the Adapt authoring tool! The Adapt team will consider all new feature requests, but unfortunately cannot commit to every one.
|
|
9
|
+
- type: textarea
|
|
10
|
+
id: description
|
|
11
|
+
attributes:
|
|
12
|
+
label: Feature description
|
|
13
|
+
description: Please describe your feature request
|
|
14
|
+
validations:
|
|
15
|
+
required: true
|
|
16
|
+
- type: checkboxes
|
|
17
|
+
id: contribute
|
|
18
|
+
attributes:
|
|
19
|
+
label: Can you work on this feature?
|
|
20
|
+
description: If you are able to commit your own time to work on this feature, it will greatly increase the liklihood of it being implemented by the core dev team. Otherwise, it will be triaged and prioritised alongside the core team's current priorities.
|
|
21
|
+
options:
|
|
22
|
+
- label: I can contribute
|
package/.github/dependabot.yml
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
-
# package ecosystems to update and where the package manifests are located.
|
|
3
|
-
# Please see the documentation for all configuration options:
|
|
4
|
-
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
-
|
|
6
|
-
version: 2
|
|
7
|
-
updates:
|
|
8
|
-
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
-
directory: "/" # Location of package manifests
|
|
10
|
-
schedule:
|
|
11
|
-
interval: "weekly"
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
schedule:
|
|
11
|
+
interval: "weekly"
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
[//]: # (Please title your PR according to eslint commit conventions)
|
|
2
|
-
[//]: # (See https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-eslint#eslint-convention for details)
|
|
3
|
-
|
|
4
|
-
[//]: # (Add a link to the original issue)
|
|
5
|
-
|
|
6
|
-
[//]: # (Delete as appropriate)
|
|
7
|
-
### Fix
|
|
8
|
-
* A sentence describing each fix
|
|
9
|
-
|
|
10
|
-
### Update
|
|
11
|
-
* A sentence describing each udpate
|
|
12
|
-
|
|
13
|
-
### New
|
|
14
|
-
* A sentence describing each new feature
|
|
15
|
-
|
|
16
|
-
### Breaking
|
|
17
|
-
* A sentence describing each breaking change
|
|
18
|
-
|
|
19
|
-
[//]: # (List appropriate steps for testing if needed)
|
|
20
|
-
### Testing
|
|
21
|
-
1. Steps for testing
|
|
22
|
-
|
|
23
|
-
[//]: # (Mention any other dependencies)
|
|
24
|
-
|
|
25
|
-
|
|
1
|
+
[//]: # (Please title your PR according to eslint commit conventions)
|
|
2
|
+
[//]: # (See https://github.com/conventional-changelog/conventional-changelog/tree/master/packages/conventional-changelog-eslint#eslint-convention for details)
|
|
3
|
+
|
|
4
|
+
[//]: # (Add a link to the original issue)
|
|
5
|
+
|
|
6
|
+
[//]: # (Delete as appropriate)
|
|
7
|
+
### Fix
|
|
8
|
+
* A sentence describing each fix
|
|
9
|
+
|
|
10
|
+
### Update
|
|
11
|
+
* A sentence describing each udpate
|
|
12
|
+
|
|
13
|
+
### New
|
|
14
|
+
* A sentence describing each new feature
|
|
15
|
+
|
|
16
|
+
### Breaking
|
|
17
|
+
* A sentence describing each breaking change
|
|
18
|
+
|
|
19
|
+
[//]: # (List appropriate steps for testing if needed)
|
|
20
|
+
### Testing
|
|
21
|
+
1. Steps for testing
|
|
22
|
+
|
|
23
|
+
[//]: # (Mention any other dependencies)
|
|
24
|
+
|
|
25
|
+
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
name: Label PRs to allow add-to-project to run
|
|
2
|
-
|
|
3
|
-
permissions:
|
|
4
|
-
pull-requests: write
|
|
5
|
-
|
|
6
|
-
on:
|
|
7
|
-
schedule:
|
|
8
|
-
- cron: '0 6 * * *'
|
|
9
|
-
|
|
10
|
-
jobs:
|
|
11
|
-
add-to-project-label:
|
|
12
|
-
name: Add label after a day
|
|
13
|
-
runs-on: ubuntu-latest
|
|
14
|
-
steps:
|
|
15
|
-
- uses: actions/stale@v9
|
|
16
|
-
with:
|
|
17
|
-
days-before-stale: 1
|
|
18
|
-
stale-pr-label: 'sorted'
|
|
1
|
+
name: Label PRs to allow add-to-project to run
|
|
2
|
+
|
|
3
|
+
permissions:
|
|
4
|
+
pull-requests: write
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
schedule:
|
|
8
|
+
- cron: '0 6 * * *'
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
add-to-project-label:
|
|
12
|
+
name: Add label after a day
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/stale@v9
|
|
16
|
+
with:
|
|
17
|
+
days-before-stale: 1
|
|
18
|
+
stale-pr-label: 'sorted'
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
-
|
|
10
|
-
|
|
11
|
-
jobs:
|
|
12
|
-
add-to-project:
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- uses: actions/add-to-project@v0.1.0
|
|
17
|
-
with:
|
|
18
|
-
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
19
|
-
github-token: ${{ secrets.PROJECTS_SECRET }}
|
|
1
|
+
# Calls the org-level reusable workflow to add PRs to the TODO Board
|
|
2
|
+
|
|
3
|
+
name: Add PR to Project
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
types:
|
|
8
|
+
- opened
|
|
9
|
+
- reopened
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
add-to-project:
|
|
13
|
+
uses: adapt-security/.github/.github/workflows/new.yml@main
|
|
14
|
+
secrets:
|
|
15
|
+
PROJECTS_SECRET: ${{ secrets.PROJECTS_SECRET }}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches:
|
|
5
|
+
- master
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
release:
|
|
9
|
+
name: Release
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
permissions:
|
|
12
|
+
contents: write # to be able to publish a GitHub release
|
|
13
|
+
issues: write # to be able to comment on released issues
|
|
14
|
+
pull-requests: write # to be able to comment on released pull requests
|
|
15
|
+
id-token: write # to enable use of OIDC for trusted publishing and npm provenance
|
|
16
|
+
steps:
|
|
17
|
+
- name: Checkout
|
|
18
|
+
uses: actions/checkout@v3
|
|
19
|
+
with:
|
|
20
|
+
fetch-depth: 0
|
|
21
|
+
- name: Setup Node.js
|
|
22
|
+
uses: actions/setup-node@v3
|
|
23
|
+
with:
|
|
24
|
+
node-version: 'lts/*'
|
|
25
|
+
- name: Update npm
|
|
26
|
+
run: npm install -g npm@latest
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: npm ci
|
|
29
|
+
- name: Release
|
|
30
|
+
env:
|
|
31
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
32
|
+
run: npx semantic-release
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
name: Standard.js formatting check
|
|
2
|
+
on: push
|
|
3
|
+
jobs:
|
|
4
|
+
default:
|
|
5
|
+
runs-on: ubuntu-latest
|
|
6
|
+
steps:
|
|
7
|
+
- uses: actions/checkout@master
|
|
8
|
+
- uses: actions/setup-node@master
|
|
9
|
+
with:
|
|
10
|
+
node-version: 'lts/*'
|
|
11
|
+
cache: 'npm'
|
|
12
|
+
- run: npm ci
|
|
13
|
+
- run: npx standard
|
package/adapt-authoring.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
{
|
|
2
|
-
"documentation": {
|
|
3
|
-
"enable": true
|
|
4
|
-
}
|
|
5
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"documentation": {
|
|
3
|
+
"enable": true
|
|
4
|
+
}
|
|
5
|
+
}
|
package/conf/config.schema.json
CHANGED
|
@@ -1,38 +1,38 @@
|
|
|
1
|
-
{
|
|
2
|
-
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
-
"type": "object",
|
|
4
|
-
"properties": {
|
|
5
|
-
"acceptedTypes": {
|
|
6
|
-
"description": "Content types the API accepts (may use MIME types or extension names)",
|
|
7
|
-
"type": "array",
|
|
8
|
-
"items": { "type": "string" },
|
|
9
|
-
"default": ["application/json"]
|
|
10
|
-
},
|
|
11
|
-
"apiRequestLimit": {
|
|
12
|
-
"description": "The number of API requests allowed by a single IP within the specified time limit",
|
|
13
|
-
"type": "number",
|
|
14
|
-
"default":
|
|
15
|
-
},
|
|
16
|
-
"apiRequestLimitDuration": {
|
|
17
|
-
"description": "Amount of time before the request count is reset",
|
|
18
|
-
"type": "string",
|
|
19
|
-
"isTimeMs": true,
|
|
20
|
-
"default": "1s"
|
|
21
|
-
},
|
|
22
|
-
"fileUploadMaxFileSize": {
|
|
23
|
-
"description": "Default file size limit for uploaded files. Note that other modules may specify their own limits, please check full config documentation for details.",
|
|
24
|
-
"type": "string",
|
|
25
|
-
"isBytes": true,
|
|
26
|
-
"default": "50mb",
|
|
27
|
-
"_adapt": {
|
|
28
|
-
"isPublic": true
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
"uploadTempDir": {
|
|
32
|
-
"description": "Temporary directory for file uploads",
|
|
33
|
-
"type": "string",
|
|
34
|
-
"isDirectory": true,
|
|
35
|
-
"default": "$TEMP/file-uploads"
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"type": "object",
|
|
4
|
+
"properties": {
|
|
5
|
+
"acceptedTypes": {
|
|
6
|
+
"description": "Content types the API accepts (may use MIME types or extension names)",
|
|
7
|
+
"type": "array",
|
|
8
|
+
"items": { "type": "string" },
|
|
9
|
+
"default": ["application/json"]
|
|
10
|
+
},
|
|
11
|
+
"apiRequestLimit": {
|
|
12
|
+
"description": "The number of API requests allowed by a single IP within the specified time limit",
|
|
13
|
+
"type": "number",
|
|
14
|
+
"default": 250
|
|
15
|
+
},
|
|
16
|
+
"apiRequestLimitDuration": {
|
|
17
|
+
"description": "Amount of time before the request count is reset",
|
|
18
|
+
"type": "string",
|
|
19
|
+
"isTimeMs": true,
|
|
20
|
+
"default": "1s"
|
|
21
|
+
},
|
|
22
|
+
"fileUploadMaxFileSize": {
|
|
23
|
+
"description": "Default file size limit for uploaded files. Note that other modules may specify their own limits, please check full config documentation for details.",
|
|
24
|
+
"type": "string",
|
|
25
|
+
"isBytes": true,
|
|
26
|
+
"default": "50mb",
|
|
27
|
+
"_adapt": {
|
|
28
|
+
"isPublic": true
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"uploadTempDir": {
|
|
32
|
+
"description": "Temporary directory for file uploads",
|
|
33
|
+
"type": "string",
|
|
34
|
+
"isDirectory": true,
|
|
35
|
+
"default": "$TEMP/file-uploads"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
package/errors/errors.json
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"BODY_PARSE_FAILED": {
|
|
3
|
-
"data": {
|
|
4
|
-
"error": "The error message"
|
|
5
|
-
},
|
|
6
|
-
"description": "Failed to parse request body data",
|
|
7
|
-
"statusCode": 400
|
|
8
|
-
},
|
|
9
|
-
"FILE_EXCEEDS_MAX_SIZE": {
|
|
10
|
-
"data": {
|
|
11
|
-
"maxSize": "The maximum file size",
|
|
12
|
-
"size": "Size of file"
|
|
13
|
-
},
|
|
14
|
-
"description": "Uploaded file exceeds the size limit",
|
|
15
|
-
"statusCode": 413
|
|
16
|
-
},
|
|
17
|
-
"RATE_LIMIT_EXCEEDED": {
|
|
18
|
-
"description": "API rate limit has been exceeded",
|
|
19
|
-
"statusCode": 429
|
|
20
|
-
},
|
|
21
|
-
"UNEXPECTED_FILE_TYPES": {
|
|
22
|
-
"data": {
|
|
23
|
-
"expectedFileTypes": "The list of expected file types",
|
|
24
|
-
"invalidFiles": "The list of invalid files"
|
|
25
|
-
},
|
|
26
|
-
"description": "Recieved unexpected file types",
|
|
27
|
-
"statusCode": 400
|
|
28
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"BODY_PARSE_FAILED": {
|
|
3
|
+
"data": {
|
|
4
|
+
"error": "The error message"
|
|
5
|
+
},
|
|
6
|
+
"description": "Failed to parse request body data",
|
|
7
|
+
"statusCode": 400
|
|
8
|
+
},
|
|
9
|
+
"FILE_EXCEEDS_MAX_SIZE": {
|
|
10
|
+
"data": {
|
|
11
|
+
"maxSize": "The maximum file size",
|
|
12
|
+
"size": "Size of file"
|
|
13
|
+
},
|
|
14
|
+
"description": "Uploaded file exceeds the size limit",
|
|
15
|
+
"statusCode": 413
|
|
16
|
+
},
|
|
17
|
+
"RATE_LIMIT_EXCEEDED": {
|
|
18
|
+
"description": "API rate limit has been exceeded",
|
|
19
|
+
"statusCode": 429
|
|
20
|
+
},
|
|
21
|
+
"UNEXPECTED_FILE_TYPES": {
|
|
22
|
+
"data": {
|
|
23
|
+
"expectedFileTypes": "The list of expected file types",
|
|
24
|
+
"invalidFiles": "The list of invalid files"
|
|
25
|
+
},
|
|
26
|
+
"description": "Recieved unexpected file types",
|
|
27
|
+
"statusCode": 400
|
|
28
|
+
}
|
|
29
29
|
}
|
package/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Reusable Express.js middleware
|
|
3
|
-
* @namespace middleware
|
|
4
|
-
*/
|
|
5
|
-
export { default } from './lib/MiddlewareModule.js'
|
|
1
|
+
/**
|
|
2
|
+
* Reusable Express.js middleware
|
|
3
|
+
* @namespace middleware
|
|
4
|
+
*/
|
|
5
|
+
export { default } from './lib/MiddlewareModule.js'
|
package/lib/MiddlewareModule.js
CHANGED
|
@@ -1,278 +1,282 @@
|
|
|
1
|
-
import { AbstractModule, App } from 'adapt-authoring-core'
|
|
2
|
-
import axios from 'axios'
|
|
3
|
-
import bodyParser from 'body-parser'
|
|
4
|
-
import bytes from 'bytes'
|
|
5
|
-
import compression from 'compression'
|
|
6
|
-
import { createWriteStream } from 'fs'
|
|
7
|
-
import { fileTypeFromFile } from 'file-type'
|
|
8
|
-
import formidable from 'formidable'
|
|
9
|
-
import fs from 'fs/promises'
|
|
10
|
-
import path from 'path'
|
|
11
|
-
import helmet from 'helmet'
|
|
12
|
-
import { RateLimiterMongo } from 'rate-limiter-flexible'
|
|
13
|
-
import { unzip } from 'zipper'
|
|
14
|
-
/**
|
|
15
|
-
* Adds useful Express middleware to the server stack
|
|
16
|
-
* @memberof middleware
|
|
17
|
-
* @extends {AbstractModule}
|
|
18
|
-
*/
|
|
19
|
-
class MiddlewareModule extends AbstractModule {
|
|
20
|
-
get zipTypes () {
|
|
21
|
-
return [
|
|
22
|
-
'application/zip',
|
|
23
|
-
'application/x-zip-compressed'
|
|
24
|
-
]
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
isZip (mimeType) {
|
|
28
|
-
return this.zipTypes.includes(mimeType)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** @override */
|
|
32
|
-
async init () {
|
|
33
|
-
const server = await this.app.waitForModule('server')
|
|
34
|
-
const helmetFunc = helmet({
|
|
35
|
-
xFrameOptions: false
|
|
36
|
-
})
|
|
37
|
-
// add custom middleware
|
|
38
|
-
// server.root.addMiddleware(helmetFunc)
|
|
39
|
-
server.api.addMiddleware(
|
|
40
|
-
helmetFunc,
|
|
41
|
-
this.rateLimiter(),
|
|
42
|
-
this.bodyParserJson(),
|
|
43
|
-
this.bodyParserUrlEncoded(),
|
|
44
|
-
compression()
|
|
45
|
-
)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Limits how many requests indivual IPs can make
|
|
50
|
-
* @return {Function} Express middleware function
|
|
51
|
-
*/
|
|
52
|
-
async rateLimiter () {
|
|
53
|
-
const
|
|
54
|
-
const { db } = await mongodb.getStats()
|
|
55
|
-
const rateLimiter = new RateLimiterMongo({
|
|
56
|
-
storeClient: mongodb.client,
|
|
57
|
-
dbName: db,
|
|
58
|
-
keyPrefix: 'ratelimiter',
|
|
59
|
-
points: this.getConfig('apiRequestLimit'),
|
|
60
|
-
duration: this.getConfig('apiRequestLimitDuration') / 1000
|
|
61
|
-
})
|
|
62
|
-
return async (req, res, next) => {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
'
|
|
69
|
-
'X-RateLimit-
|
|
70
|
-
'X-RateLimit-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
*
|
|
82
|
-
* @
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
next(
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if (
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
if (
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
f.mimetype
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
*
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
if (
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
1
|
+
import { AbstractModule, App } from 'adapt-authoring-core'
|
|
2
|
+
import axios from 'axios'
|
|
3
|
+
import bodyParser from 'body-parser'
|
|
4
|
+
import bytes from 'bytes'
|
|
5
|
+
import compression from 'compression'
|
|
6
|
+
import { createWriteStream } from 'fs'
|
|
7
|
+
import { fileTypeFromFile } from 'file-type'
|
|
8
|
+
import formidable from 'formidable'
|
|
9
|
+
import fs from 'fs/promises'
|
|
10
|
+
import path from 'path'
|
|
11
|
+
import helmet from 'helmet'
|
|
12
|
+
import { RateLimiterMongo } from 'rate-limiter-flexible'
|
|
13
|
+
import { unzip } from 'zipper'
|
|
14
|
+
/**
|
|
15
|
+
* Adds useful Express middleware to the server stack
|
|
16
|
+
* @memberof middleware
|
|
17
|
+
* @extends {AbstractModule}
|
|
18
|
+
*/
|
|
19
|
+
class MiddlewareModule extends AbstractModule {
|
|
20
|
+
get zipTypes () {
|
|
21
|
+
return [
|
|
22
|
+
'application/zip',
|
|
23
|
+
'application/x-zip-compressed'
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
isZip (mimeType) {
|
|
28
|
+
return this.zipTypes.includes(mimeType)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** @override */
|
|
32
|
+
async init () {
|
|
33
|
+
const server = await this.app.waitForModule('server')
|
|
34
|
+
const helmetFunc = helmet({
|
|
35
|
+
xFrameOptions: false
|
|
36
|
+
})
|
|
37
|
+
// add custom middleware
|
|
38
|
+
// server.root.addMiddleware(helmetFunc)
|
|
39
|
+
server.api.addMiddleware(
|
|
40
|
+
helmetFunc,
|
|
41
|
+
this.rateLimiter(),
|
|
42
|
+
this.bodyParserJson(),
|
|
43
|
+
this.bodyParserUrlEncoded(),
|
|
44
|
+
compression()
|
|
45
|
+
)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Limits how many requests indivual IPs can make
|
|
50
|
+
* @return {Function} Express middleware function
|
|
51
|
+
*/
|
|
52
|
+
async rateLimiter () {
|
|
53
|
+
const mongodb = await this.app.waitForModule('mongodb')
|
|
54
|
+
const { db } = await mongodb.getStats()
|
|
55
|
+
const rateLimiter = new RateLimiterMongo({
|
|
56
|
+
storeClient: mongodb.client,
|
|
57
|
+
dbName: db,
|
|
58
|
+
keyPrefix: 'ratelimiter',
|
|
59
|
+
points: this.getConfig('apiRequestLimit'),
|
|
60
|
+
duration: this.getConfig('apiRequestLimitDuration') / 1000
|
|
61
|
+
})
|
|
62
|
+
return async (req, res, next) => {
|
|
63
|
+
let resetAt
|
|
64
|
+
try {
|
|
65
|
+
const data = await rateLimiter.consume(req.ip)
|
|
66
|
+
resetAt = new Date(Date.now() + data.msBeforeNext)
|
|
67
|
+
res.set({
|
|
68
|
+
'Retry-After': data.msBeforeNext / 1000,
|
|
69
|
+
'X-RateLimit-Limit': this.getConfig('apiRequestLimit'),
|
|
70
|
+
'X-RateLimit-Remaining': data.remainingPoints,
|
|
71
|
+
'X-RateLimit-Reset': resetAt
|
|
72
|
+
})
|
|
73
|
+
next()
|
|
74
|
+
} catch (e) {
|
|
75
|
+
res.sendError(this.app.errors.RATE_LIMIT_EXCEEDED.setData({ url: req.url, resetAt }))
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Parses incoming JSON data to req.body
|
|
82
|
+
* @see https://github.com/expressjs/body-parser#bodyparserjsonoptions
|
|
83
|
+
* @return {Function} Express middleware function
|
|
84
|
+
*/
|
|
85
|
+
bodyParserJson () {
|
|
86
|
+
return (req, res, next) => {
|
|
87
|
+
bodyParser.json()(req, res, (error, ...args) => {
|
|
88
|
+
if (error) return next(this.app.errors.BODY_PARSE_FAILED.setData({ error: error.message }))
|
|
89
|
+
if (req.body === undefined) req.body = {}
|
|
90
|
+
next(null, ...args)
|
|
91
|
+
})
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Parses incoming URL-encoded data to req.body
|
|
97
|
+
* @see https://github.com/expressjs/body-parser#bodyparserurlencodedoptions
|
|
98
|
+
* @return {Function} Express middleware function
|
|
99
|
+
*/
|
|
100
|
+
bodyParserUrlEncoded () {
|
|
101
|
+
return (req, res, next) => {
|
|
102
|
+
bodyParser.urlencoded({ extended: true })(req, res, (error, ...args) => {
|
|
103
|
+
if (error) return next(this.app.errors.BODY_PARSE_FAILED.setData({ error: error.message }))
|
|
104
|
+
next(null, ...args)
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Sets default file upload options
|
|
111
|
+
* @param {object} options The initial options object
|
|
112
|
+
* @returns {FileUploadOptions}
|
|
113
|
+
*/
|
|
114
|
+
setDefaultFileOptions (options = {}) {
|
|
115
|
+
Object.entries({
|
|
116
|
+
maxFileSize: this.getConfig('fileUploadMaxFileSize'),
|
|
117
|
+
multiples: true,
|
|
118
|
+
uploadDir: this.getConfig('uploadTempDir'),
|
|
119
|
+
promisify: false,
|
|
120
|
+
unzip: false,
|
|
121
|
+
removeZipSource: true
|
|
122
|
+
}).forEach(([k, v]) => {
|
|
123
|
+
if (k === 'expectedFileTypes' && !Array.isArray(v)) v = [v]
|
|
124
|
+
if (!Object.prototype.hasOwnProperty.call(options, k)) options[k] = v
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Handles incoming file uploads
|
|
130
|
+
* @param {Array<String>} expectedFileTypes List of file types to accept
|
|
131
|
+
* @param {FileUploadOptions} options
|
|
132
|
+
* @return {Function} The Express handler
|
|
133
|
+
*/
|
|
134
|
+
fileUploadParser (expectedFileTypes, options = {}) {
|
|
135
|
+
options.expectedFileTypes = expectedFileTypes
|
|
136
|
+
return (req, res, next) => {
|
|
137
|
+
// Below is wrapped in a promise so other code can use the Promise interface rather than a standard callback
|
|
138
|
+
return new Promise(async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
|
|
139
|
+
const middleware = await App.instance.waitForModule('middleware')
|
|
140
|
+
middleware.setDefaultFileOptions(options)
|
|
141
|
+
|
|
142
|
+
if (options.promisify) {
|
|
143
|
+
next = e => e ? reject(e) : resolve()
|
|
144
|
+
}
|
|
145
|
+
if (!req.headers['content-type']?.startsWith('multipart/form-data')) {
|
|
146
|
+
return next()
|
|
147
|
+
}
|
|
148
|
+
try {
|
|
149
|
+
await fs.mkdir(options.uploadDir, { recursive: true })
|
|
150
|
+
} catch (e) {
|
|
151
|
+
if (e.code !== 'EEXIST') return next(e)
|
|
152
|
+
}
|
|
153
|
+
formidable(options).parse(req, async (error, fields, files) => {
|
|
154
|
+
if (error) {
|
|
155
|
+
if (error.code === 1009) {
|
|
156
|
+
const [maxSize, size] = error.message.match(/(\d+) bytes/g).map(s => bytes(Number(s.replace(' bytes', ''))))
|
|
157
|
+
error = App.instance.errors.FILE_EXCEEDS_MAX_SIZE.setData({ maxSize, size })
|
|
158
|
+
}
|
|
159
|
+
return next(error)
|
|
160
|
+
}
|
|
161
|
+
// covert fields back from arrays and add to body
|
|
162
|
+
Object.keys(fields).forEach(k => {
|
|
163
|
+
let val = fields[k][0]
|
|
164
|
+
try { val = JSON.parse(val) } catch (e) {}
|
|
165
|
+
req.body[k] = val
|
|
166
|
+
})
|
|
167
|
+
if (Object.keys(files).length === 0) { // no files uploaded
|
|
168
|
+
return next()
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
await validateUploadedFiles(req, files, options)
|
|
172
|
+
} catch (e) {
|
|
173
|
+
return next(e)
|
|
174
|
+
}
|
|
175
|
+
if (options.unzip) {
|
|
176
|
+
await Promise.all(Object.entries(files).map(async ([k, [f]]) => {
|
|
177
|
+
if (!middleware.isZip(f.mimetype)) {
|
|
178
|
+
return Promise.resolve()
|
|
179
|
+
}
|
|
180
|
+
f.mimetype = 'application/zip' // always set to the same value for easier checking elsewhere
|
|
181
|
+
f.filepath = await unzip(f.filepath, `${f.filepath}_unzip`, { removeSource: options.removeZipSource || true })
|
|
182
|
+
}))
|
|
183
|
+
}
|
|
184
|
+
Object.assign(req, { fileUpload: { files } })
|
|
185
|
+
next()
|
|
186
|
+
})
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Handles incoming file uploads via URL
|
|
193
|
+
* @param {Array<String>} expectedFileTypes List of file types to accept
|
|
194
|
+
* @param {FileUploadOptions} options
|
|
195
|
+
* @return {Function} The Express handler
|
|
196
|
+
*/
|
|
197
|
+
urlUploadParser (expectedFileTypes, options) {
|
|
198
|
+
options.expectedFileTypes = expectedFileTypes
|
|
199
|
+
return (req, res, next) => {
|
|
200
|
+
// Below is wrapped in a promise so other code can use the Promise interface rather than a standard callback
|
|
201
|
+
return new Promise(async (resolve, reject) => { // eslint-disable-line no-async-promise-executor
|
|
202
|
+
const middleware = await App.instance.waitForModule('middleware')
|
|
203
|
+
middleware.setDefaultFileOptions(options)
|
|
204
|
+
|
|
205
|
+
if (options.promisify) {
|
|
206
|
+
next = e => e ? reject(e) : resolve()
|
|
207
|
+
}
|
|
208
|
+
if (!req.body.url) {
|
|
209
|
+
return next()
|
|
210
|
+
}
|
|
211
|
+
let responseData
|
|
212
|
+
try {
|
|
213
|
+
responseData = (await axios.get(req.body.url, { responseType: 'stream' })).data
|
|
214
|
+
} catch (e) {
|
|
215
|
+
if (e.code === 'ERR_INVALID_URL' || e.response.status === 404) {
|
|
216
|
+
return next(this.app.errors.INVALID_ASSET_URL.setData({ url: req.body.url }))
|
|
217
|
+
}
|
|
218
|
+
return next(e)
|
|
219
|
+
}
|
|
220
|
+
const contentType = responseData.headers['content-type']
|
|
221
|
+
const subtype = contentType.split('/')[1]
|
|
222
|
+
const fileName = `${new Date().getTime()}.${subtype}`
|
|
223
|
+
const uploadPath = path.resolve(options.uploadDir, fileName)
|
|
224
|
+
// set up file data to mimic formidable
|
|
225
|
+
const fileData = {
|
|
226
|
+
fields: req.apiData.data,
|
|
227
|
+
files: {
|
|
228
|
+
file: [{
|
|
229
|
+
filepath: uploadPath,
|
|
230
|
+
originalFilename: fileName,
|
|
231
|
+
newFilename: fileName,
|
|
232
|
+
mimetype: contentType,
|
|
233
|
+
size: Number(responseData.headers['content-length'])
|
|
234
|
+
}]
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
let fileStream
|
|
238
|
+
try {
|
|
239
|
+
validateUploadedFiles(req, fileData.files, options)
|
|
240
|
+
await fs.mkdir(options.uploadDir, { recursive: true })
|
|
241
|
+
fileStream = createWriteStream(uploadPath)
|
|
242
|
+
} catch (e) {
|
|
243
|
+
if (e.code !== 'EEXIST') return next(e)
|
|
244
|
+
}
|
|
245
|
+
responseData.pipe(fileStream).on('close', async () => {
|
|
246
|
+
req.fileUpload = fileData
|
|
247
|
+
if (subtype === 'zip' && options.unzip) {
|
|
248
|
+
req.fileUpload.files.course.filepath = await unzip(uploadPath, `${uploadPath}_unzip`, { removeSource: options.removeSource })
|
|
249
|
+
}
|
|
250
|
+
next()
|
|
251
|
+
}).on('error', next)
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
/** @ignore */
|
|
257
|
+
async function validateUploadedFiles (req, filesObj, options) {
|
|
258
|
+
const errors = App.instance.errors
|
|
259
|
+
const assetErrors = []
|
|
260
|
+
const filesArr = Object.values(filesObj).reduce((memo, f) => memo.concat(f), []) // flatten nested arrays
|
|
261
|
+
await Promise.all(filesArr.map(async f => {
|
|
262
|
+
if (!options.expectedFileTypes.includes(f.mimetype)) {
|
|
263
|
+
// formidable mimetype isn't allowed, try inspecting the file
|
|
264
|
+
f.mimetype = (await fileTypeFromFile(f.filepath))?.mime
|
|
265
|
+
if (!f.mimetype && path.extname(f.originalFilename) === '.srt') {
|
|
266
|
+
f.mimetype = 'application/x-subrip'
|
|
267
|
+
}
|
|
268
|
+
if (!options.expectedFileTypes.includes(f.mimetype)) {
|
|
269
|
+
assetErrors.push(errors.UNEXPECTED_FILE_TYPES.setData({ expectedFileTypes: options.expectedFileTypes, invalidFiles: [f.originalFilename], mimetypes: [f.mimetype] }))
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (!f.size > options.maxFileSize) {
|
|
273
|
+
assetErrors.push(errors.FILE_EXCEEDS_MAX_SIZE.setData({ size: bytes(f.size), maxSize: bytes(options.maxFileSize) }))
|
|
274
|
+
}
|
|
275
|
+
}))
|
|
276
|
+
if (assetErrors.length) {
|
|
277
|
+
throw errors.VALIDATION_FAILED
|
|
278
|
+
.setData({ schemaName: 'fileupload', errors: assetErrors.map(req.translate).join(', ') })
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
export default MiddlewareModule
|
package/lib/typedefs.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file exists to define the below types for documentation purposes.
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* Options which can be passed to file upload middleware
|
|
6
|
-
* @memberof middleware
|
|
7
|
-
* @typedef {Object} FileUploadOptions
|
|
8
|
-
* @property {number} maxFileSize Maximum file size allowed by upload
|
|
9
|
-
* @property {string} uploadDir Directory file upload should be stored
|
|
10
|
-
* @property {Boolean} promisify If true, middleware will return a promise rather than use the standard callback. Useful when calling middleware outside of an Express middleware stack
|
|
11
|
-
* @property {Boolean} removeZipSource To be used in conjunction with the unzip option. Whether the original zip file should be removed after unzipping (true by default)
|
|
12
|
-
* @property {Boolean} unzip Whether any zip files should be unzipped by the handler
|
|
13
|
-
*/
|
|
1
|
+
/**
|
|
2
|
+
* This file exists to define the below types for documentation purposes.
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Options which can be passed to file upload middleware
|
|
6
|
+
* @memberof middleware
|
|
7
|
+
* @typedef {Object} FileUploadOptions
|
|
8
|
+
* @property {number} maxFileSize Maximum file size allowed by upload
|
|
9
|
+
* @property {string} uploadDir Directory file upload should be stored
|
|
10
|
+
* @property {Boolean} promisify If true, middleware will return a promise rather than use the standard callback. Useful when calling middleware outside of an Express middleware stack
|
|
11
|
+
* @property {Boolean} removeZipSource To be used in conjunction with the unzip option. Whether the original zip file should be removed after unzipping (true by default)
|
|
12
|
+
* @property {Boolean} unzip Whether any zip files should be unzipped by the handler
|
|
13
|
+
*/
|
package/package.json
CHANGED
|
@@ -1,29 +1,63 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "adapt-authoring-middleware",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Express middleware to be added to the server",
|
|
5
|
-
"homepage": "https://github.com/adapt-security/adapt-authoring-middleware",
|
|
6
|
-
"license": "GPL-3.0",
|
|
7
|
-
"type": "module",
|
|
8
|
-
"main": "index.js",
|
|
9
|
-
"repository": "github:adapt-security/adapt-authoring-middleware",
|
|
10
|
-
"dependencies": {
|
|
11
|
-
"axios": "^1.6.7",
|
|
12
|
-
"body-parser": "^
|
|
13
|
-
"bytes": "^3.1.2",
|
|
14
|
-
"compression": "^1.7.4",
|
|
15
|
-
"file-type": "^20.5.0",
|
|
16
|
-
"formidable": "^3.5.1",
|
|
17
|
-
"helmet": "^8.0.0",
|
|
18
|
-
"lodash": "^4.17.21",
|
|
19
|
-
"rate-limiter-flexible": "^
|
|
20
|
-
"zipper": "github:adapt-security/zipper"
|
|
21
|
-
},
|
|
22
|
-
"peerDependencies": {
|
|
23
|
-
"adapt-authoring-core": "
|
|
24
|
-
},
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "adapt-authoring-middleware",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Express middleware to be added to the server",
|
|
5
|
+
"homepage": "https://github.com/adapt-security/adapt-authoring-middleware",
|
|
6
|
+
"license": "GPL-3.0",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "index.js",
|
|
9
|
+
"repository": "github:adapt-security/adapt-authoring-middleware",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"axios": "^1.6.7",
|
|
12
|
+
"body-parser": "^2.2.2",
|
|
13
|
+
"bytes": "^3.1.2",
|
|
14
|
+
"compression": "^1.7.4",
|
|
15
|
+
"file-type": "^20.5.0",
|
|
16
|
+
"formidable": "^3.5.1",
|
|
17
|
+
"helmet": "^8.0.0",
|
|
18
|
+
"lodash": "^4.17.21",
|
|
19
|
+
"rate-limiter-flexible": "^8.2.0",
|
|
20
|
+
"zipper": "github:adapt-security/zipper"
|
|
21
|
+
},
|
|
22
|
+
"peerDependencies": {
|
|
23
|
+
"adapt-authoring-core": "^1.0.0"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
27
|
+
"@semantic-release/git": "^10.0.1",
|
|
28
|
+
"@semantic-release/github": "^12.0.2",
|
|
29
|
+
"@semantic-release/npm": "^13.1.2",
|
|
30
|
+
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
31
|
+
"conventional-changelog-eslint": "^6.0.0",
|
|
32
|
+
"semantic-release": "^25.0.2",
|
|
33
|
+
"semantic-release-replace-plugin": "^1.2.7",
|
|
34
|
+
"standard": "^17.1.0"
|
|
35
|
+
},
|
|
36
|
+
"release": {
|
|
37
|
+
"plugins": [
|
|
38
|
+
[
|
|
39
|
+
"@semantic-release/commit-analyzer",
|
|
40
|
+
{
|
|
41
|
+
"preset": "eslint"
|
|
42
|
+
}
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
"@semantic-release/release-notes-generator",
|
|
46
|
+
{
|
|
47
|
+
"preset": "eslint"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
"@semantic-release/npm",
|
|
51
|
+
"@semantic-release/github",
|
|
52
|
+
[
|
|
53
|
+
"@semantic-release/git",
|
|
54
|
+
{
|
|
55
|
+
"assets": [
|
|
56
|
+
"package.json"
|
|
57
|
+
],
|
|
58
|
+
"message": "Chore(release): ${nextRelease.version} [skip ci]\n\n${nextRelease.notes}"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
]
|
|
62
|
+
}
|
|
63
|
+
}
|
package/.eslintignore
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
node_modules
|
package/.eslintrc
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
name: Add labelled PRs to project
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
types: [ labeled ]
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
add-to-project:
|
|
9
|
-
if: ${{ github.event.label.name == 'dependencies' }}
|
|
10
|
-
name: Add to main project
|
|
11
|
-
runs-on: ubuntu-latest
|
|
12
|
-
steps:
|
|
13
|
-
- uses: actions/add-to-project@v0.1.0
|
|
14
|
-
with:
|
|
15
|
-
project-url: https://github.com/orgs/adapt-security/projects/5
|
|
16
|
-
github-token: ${{ secrets.PROJECTS_SECRET }}
|