added authorization
This commit is contained in:
parent
90d34f1e1b
commit
1a3fdc567d
@ -3,7 +3,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Id'
|
- $ref: 'oas.yaml#/components/parameters/Id'
|
||||||
get:
|
get:
|
||||||
summary: TODO condition by id
|
summary: TODO condition by id
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /condition
|
- /condition
|
||||||
responses:
|
responses:
|
||||||
@ -23,9 +23,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/change condition
|
summary: TODO add/change condition
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /condition
|
- /condition
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -51,9 +53,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete condition
|
summary: TODO delete condition
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /condition
|
- /condition
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Id'
|
- $ref: 'oas.yaml#/components/parameters/Id'
|
||||||
get:
|
get:
|
||||||
summary: TODO get material details
|
summary: TODO get material details
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /material
|
- /material
|
||||||
responses:
|
responses:
|
||||||
@ -21,9 +21,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/change material
|
summary: TODO add/change material
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /material
|
- /material
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -47,9 +49,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete material
|
summary: TODO delete material
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /material
|
- /material
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Id'
|
- $ref: 'oas.yaml#/components/parameters/Id'
|
||||||
get:
|
get:
|
||||||
summary: TODO measurement values by id
|
summary: TODO measurement values by id
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /measurement
|
- /measurement
|
||||||
responses:
|
responses:
|
||||||
@ -23,9 +23,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/change measurement
|
summary: TODO add/change measurement
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /measurement
|
- /measurement
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -51,9 +53,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete measurement
|
summary: TODO delete measurement
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /measurement
|
- /measurement
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Name'
|
- $ref: 'oas.yaml#/components/parameters/Name'
|
||||||
get:
|
get:
|
||||||
summary: TODO get model data by name
|
summary: TODO get model data by name
|
||||||
description: 'levels: dev, admin'
|
description: 'Auth: all, levels: dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /model
|
- /model
|
||||||
responses:
|
responses:
|
||||||
@ -24,7 +24,7 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/replace model data by name
|
summary: TODO add/replace model data by name
|
||||||
description: 'levels: dev, admin'
|
description: 'Auth: all, levels: dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /model
|
- /model
|
||||||
requestBody:
|
requestBody:
|
||||||
@ -50,9 +50,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete model data
|
summary: TODO delete model data
|
||||||
description: 'levels: dev, admin'
|
description: 'Auth: basic, levels: dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /model
|
- /model
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
|
@ -6,7 +6,10 @@ info:
|
|||||||
version: 1.0.0
|
version: 1.0.0
|
||||||
description: |
|
description: |
|
||||||
This API gives access to the project database.<br>
|
This API gives access to the project database.<br>
|
||||||
Access is restricted. Authentication can be obtained with HTTP Basic Auth using username and password. Data access methods can also be accessed using an API key at the URL ending like ?key=xxx<br>
|
Access is restricted. Authentication can be obtained with HTTP Basic Auth using username and password.
|
||||||
|
Data access methods can also be accessed using an API key at the URL ending like ?key=xxx<br>
|
||||||
|
The description lists available authentication methods, also the locks of each method close correspondingly
|
||||||
|
if the entered authentication is allowed.<br><br>
|
||||||
There are a number of different user levels: <br>
|
There are a number of different user levels: <br>
|
||||||
<ul>
|
<ul>
|
||||||
<li>read: read access to the samples database</li>
|
<li>read: read access to the samples database</li>
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
/:
|
/:
|
||||||
get:
|
get:
|
||||||
summary: Root method
|
summary: Root method
|
||||||
|
description: 'Auth: none'
|
||||||
tags:
|
tags:
|
||||||
- /
|
- /
|
||||||
security: []
|
security: []
|
||||||
@ -16,3 +17,27 @@
|
|||||||
example: 'API server up and running!'
|
example: 'API server up and running!'
|
||||||
500:
|
500:
|
||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
|
|
||||||
|
/authorized:
|
||||||
|
get:
|
||||||
|
summary: Checks authorization
|
||||||
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
|
tags:
|
||||||
|
- /
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: Authorized
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
properties:
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
example: 'Authorization successful'
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
example: 'basic'
|
||||||
|
401:
|
||||||
|
$ref: 'oas.yaml#/components/responses/401'
|
||||||
|
500:
|
||||||
|
$ref: 'oas.yaml#/components/responses/500'
|
@ -1,7 +1,7 @@
|
|||||||
/samples:
|
/samples:
|
||||||
get:
|
get:
|
||||||
summary: TODO all samples in overview
|
summary: TODO all samples in overview
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /sample
|
- /sample
|
||||||
responses:
|
responses:
|
||||||
@ -20,7 +20,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Id'
|
- $ref: 'oas.yaml#/components/parameters/Id'
|
||||||
get:
|
get:
|
||||||
summary: TODO sample details
|
summary: TODO sample details
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: all, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /sample
|
- /sample
|
||||||
responses:
|
responses:
|
||||||
@ -40,9 +40,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/change sample
|
summary: TODO add/change sample
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /sample
|
- /sample
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -68,9 +70,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete sample
|
summary: TODO delete sample
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: basic, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /sample
|
- /sample
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
@ -87,7 +91,7 @@
|
|||||||
/sample/notes/fields:
|
/sample/notes/fields:
|
||||||
get:
|
get:
|
||||||
summary: TODO list all existing field names for custom notes fields
|
summary: TODO list all existing field names for custom notes fields
|
||||||
description: 'levels: write, maintain, dev, admin'
|
description: 'Auth: all, levels: write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /sample
|
- /sample
|
||||||
responses:
|
responses:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/template/treatments:
|
/template/treatments:
|
||||||
get:
|
get:
|
||||||
summary: TODO all available treatment methods
|
summary: TODO all available treatment methods
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
security:
|
security:
|
||||||
@ -30,7 +30,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Name'
|
- $ref: 'oas.yaml#/components/parameters/Name'
|
||||||
get:
|
get:
|
||||||
summary: TODO treatment method details
|
summary: TODO treatment method details
|
||||||
description: 'levels: read, write, maintain, admin'
|
description: 'Auth: basic, levels: read, write, maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
security:
|
security:
|
||||||
@ -59,9 +59,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/change treatment method
|
summary: TODO add/change treatment method
|
||||||
description: 'levels: maintain, admin'
|
description: 'Auth: basic, levels: maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -101,9 +103,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete treatment method
|
summary: TODO delete treatment method
|
||||||
description: 'levels: maintain, admin'
|
description: 'Auth: basic, levels: maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
@ -120,7 +124,7 @@
|
|||||||
/template/measurements:
|
/template/measurements:
|
||||||
get:
|
get:
|
||||||
summary: TODO all available measurement methods
|
summary: TODO all available measurement methods
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
security:
|
security:
|
||||||
@ -150,7 +154,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Name'
|
- $ref: 'oas.yaml#/components/parameters/Name'
|
||||||
get:
|
get:
|
||||||
summary: TODO measurement method details
|
summary: TODO measurement method details
|
||||||
description: 'levels: read, write, maintain, admin'
|
description: 'Auth: basic, levels: read, write, maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
security:
|
security:
|
||||||
@ -180,9 +184,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO add/change measurement method
|
summary: TODO add/change measurement method
|
||||||
description: 'levels: maintain, admin'
|
description: 'Auth: basic, levels: maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -224,9 +230,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete measurement method
|
summary: TODO delete measurement method
|
||||||
description: 'levels: maintain, admin'
|
description: 'Auth: basic, levels: maintain, admin'
|
||||||
tags:
|
tags:
|
||||||
- /templates
|
- /templates
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/users:
|
/users:
|
||||||
get:
|
get:
|
||||||
summary: TODO lists all users
|
summary: TODO lists all users
|
||||||
description: 'levels: admin'
|
description: 'Auth: basic, levels: admin'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
security:
|
security:
|
||||||
@ -26,7 +26,7 @@
|
|||||||
- $ref: 'oas.yaml#/components/parameters/Name'
|
- $ref: 'oas.yaml#/components/parameters/Name'
|
||||||
get:
|
get:
|
||||||
summary: TODO list user details
|
summary: TODO list user details
|
||||||
description: 'levels: read, write, maintain, dev get their own information without a name property specified, level: admin can get any user using the name parameter'
|
description: 'Auth: basic, levels: read, write, maintain, dev get their own information without a name property specified, level: admin can get any user using the name parameter'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
security:
|
security:
|
||||||
@ -52,9 +52,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
put:
|
put:
|
||||||
summary: TODO change user details
|
summary: TODO change user details
|
||||||
description: 'levels: read, write, maintain, dev can change their own information (except level) without a name property specified, level: admin can change any user using the name parameter'
|
description: 'Auth: basic, levels: read, write, maintain, dev can change their own information (except level) without a name property specified, level: admin can change any user using the name parameter'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
requestBody:
|
requestBody:
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
@ -82,9 +84,11 @@
|
|||||||
$ref: 'oas.yaml#/components/responses/500'
|
$ref: 'oas.yaml#/components/responses/500'
|
||||||
delete:
|
delete:
|
||||||
summary: TODO delete user
|
summary: TODO delete user
|
||||||
description: 'levels: read, write, maintain, dev can delete their own account, level: admin can delete any user using the name parameter'
|
description: 'Auth: basic, levels: read, write, maintain, dev can delete their own account, level: admin can delete any user using the name parameter'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
|
security:
|
||||||
|
- BasicAuth: []
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
$ref: 'oas.yaml#/components/responses/Ok'
|
$ref: 'oas.yaml#/components/responses/Ok'
|
||||||
@ -101,7 +105,7 @@
|
|||||||
/user/key:
|
/user/key:
|
||||||
get:
|
get:
|
||||||
summary: TODO get API key for the user
|
summary: TODO get API key for the user
|
||||||
description: 'levels: read, write, maintain, dev, admin'
|
description: 'Auth: basic, levels: read, write, maintain, dev, admin'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
security:
|
security:
|
||||||
@ -120,7 +124,7 @@
|
|||||||
/user/new:
|
/user/new:
|
||||||
post:
|
post:
|
||||||
summary: TODO add new user
|
summary: TODO add new user
|
||||||
description: 'levels: admin'
|
description: 'Auth: basic, levels: admin'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
security:
|
security:
|
||||||
@ -157,6 +161,7 @@
|
|||||||
/user/passreset:
|
/user/passreset:
|
||||||
post:
|
post:
|
||||||
summary: TODO reset password and send mail to restore
|
summary: TODO reset password and send mail to restore
|
||||||
|
description: 'Auth: none'
|
||||||
tags:
|
tags:
|
||||||
- /user
|
- /user
|
||||||
security: []
|
security: []
|
||||||
|
18
package-lock.json
generated
18
package-lock.json
generated
@ -208,6 +208,14 @@
|
|||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
},
|
},
|
||||||
|
"basic-auth": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "5.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"bcryptjs": {
|
"bcryptjs": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
|
||||||
@ -562,6 +570,11 @@
|
|||||||
"safe-buffer": "5.1.2"
|
"safe-buffer": "5.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"content-filter": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/content-filter/-/content-filter-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-VaZ4Y7h776r0v2WxWqu3iatjYI6/N0msXK8O1ymtkFWbSvaFoCePksS8U60BS6dUMZeAlqhN09SuM7ghdzRP1Q=="
|
||||||
|
},
|
||||||
"content-type": {
|
"content-type": {
|
||||||
"version": "1.0.4",
|
"version": "1.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
|
||||||
@ -1440,6 +1453,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"mongo-sanitize": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/mongo-sanitize/-/mongo-sanitize-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-6gB9AiJD+om2eZLxaPKIP5Q8P3Fr+s+17rVWso7hU0+MAzmIvIMlgTYuyvalDLTtE/p0gczcvJ8A3pbN1XmQ/A=="
|
||||||
|
},
|
||||||
"mongodb": {
|
"mongodb": {
|
||||||
"version": "3.4.1",
|
"version": "3.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.4.1.tgz",
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
"description": "API for the digital fingerprint of plastics mongodb",
|
"description": "API for the digital fingerprint of plastics mongodb",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
"tsc": "tsc",
|
||||||
"test": "mocha dist/**/**.spec.js",
|
"test": "mocha dist/**/**.spec.js",
|
||||||
"start": "tsc && node dist/index.js",
|
"start": "tsc && node dist/index.js",
|
||||||
"dev": "nodemon -e ts,yaml --exec \"npm run start\""
|
"dev": "nodemon -e ts,yaml --exec \"npm run start\""
|
||||||
@ -16,11 +17,14 @@
|
|||||||
"@hapi/joi": "^17.1.1",
|
"@hapi/joi": "^17.1.1",
|
||||||
"@types/mocha": "^5.2.7",
|
"@types/mocha": "^5.2.7",
|
||||||
"@types/node": "^13.1.6",
|
"@types/node": "^13.1.6",
|
||||||
|
"basic-auth": "^2.0.1",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"body-parser": "^1.19.0",
|
"body-parser": "^1.19.0",
|
||||||
"cfenv": "^1.2.2",
|
"cfenv": "^1.2.2",
|
||||||
|
"content-filter": "^1.1.2",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
"json-schema": "^0.2.5",
|
"json-schema": "^0.2.5",
|
||||||
|
"mongo-sanitize": "^1.1.0",
|
||||||
"mongoose": "^5.8.7",
|
"mongoose": "^5.8.7",
|
||||||
"nodemon": "^2.0.3",
|
"nodemon": "^2.0.3",
|
||||||
"swagger-ui-express": "^4.1.2",
|
"swagger-ui-express": "^4.1.2",
|
||||||
|
11
src/db.ts
11
src/db.ts
@ -39,6 +39,17 @@ export default class db {
|
|||||||
if (err) done(err);
|
if (err) done(err);
|
||||||
});
|
});
|
||||||
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
mongoose.connection.on('error', console.error.bind(console, 'connection error:'));
|
||||||
|
mongoose.connection.on('disconnected', () => { // reset state on disconnect
|
||||||
|
console.log('Database disconnected');
|
||||||
|
this.state.db = 0;
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
process.on('SIGINT', () => { // close connection when app is terminated
|
||||||
|
mongoose.connection.close(() => {
|
||||||
|
console.log('Mongoose default connection disconnected through app termination');
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
mongoose.connection.once('open', () => {
|
mongoose.connection.once('open', () => {
|
||||||
console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`);
|
console.log(process.env.NODE_ENV === 'test' ? '' : `Connected to ${connectionString}`);
|
||||||
this.state.db = mongoose.connection;
|
this.state.db = mongoose.connection;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const globals = {
|
const globals = {
|
||||||
levels: [
|
levels: [ // access levels
|
||||||
'read',
|
'read',
|
||||||
'write',
|
'write',
|
||||||
'maintain',
|
'maintain',
|
||||||
|
100
src/helpers/authorize.ts
Normal file
100
src/helpers/authorize.ts
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import basicAuth from 'basic-auth';
|
||||||
|
import bcrypt from 'bcryptjs';
|
||||||
|
import UserModel from '../models/user';
|
||||||
|
|
||||||
|
|
||||||
|
// appends req.auth(res, ['levels'], method = 'all')
|
||||||
|
// which returns sends error message and returns false if unauthorized, otherwise true
|
||||||
|
// req.authDetails returns eg. {methods: ['basic'], username: 'johndoe', level: 'write'}
|
||||||
|
|
||||||
|
module.exports = async (req, res, next) => {
|
||||||
|
let givenMethod = ''; // authorization method given by client, basic taken preferred
|
||||||
|
let user = {name: '', level: ''}; // user object
|
||||||
|
|
||||||
|
// test authentications
|
||||||
|
const userBasic = await basic(req, next);
|
||||||
|
|
||||||
|
if (userBasic) { // basic available
|
||||||
|
givenMethod = 'basic';
|
||||||
|
user = userBasic;
|
||||||
|
}
|
||||||
|
else { // if basic not available, test key
|
||||||
|
const userKey = await key(req, next);
|
||||||
|
if (userKey) {
|
||||||
|
givenMethod = 'key';
|
||||||
|
user = userKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.auth = (res, levels, method = 'all') => {
|
||||||
|
if (givenMethod === method || (method === 'all' && givenMethod !== '')) { // method is available
|
||||||
|
if (levels.indexOf(user.level) > -1) { // level is available
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(403).json({status: 'Forbidden'});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(401).json({status: 'Unauthorized'});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
req.authDetails = {
|
||||||
|
method: givenMethod,
|
||||||
|
username: user.name,
|
||||||
|
level: user.level
|
||||||
|
};
|
||||||
|
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function basic (req, next): any { // checks basic auth and returns changed user object
|
||||||
|
return new Promise(resolve => {
|
||||||
|
const auth = basicAuth(req);
|
||||||
|
if (auth !== undefined) { // basic auth available
|
||||||
|
UserModel.find({name: auth.name}).lean().exec( 'find', (err, data) => { // find user
|
||||||
|
if (err) next(err);
|
||||||
|
if (data.length === 1) { // one user found
|
||||||
|
bcrypt.compare(auth.pass, data[0].pass, (err, res) => { // check password
|
||||||
|
if (err) next(err);
|
||||||
|
if (res === true) {
|
||||||
|
resolve({level: data[0].level, name: data[0].name});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function key (req, next): any { // checks API key and returns changed user object
|
||||||
|
return new Promise(resolve => {
|
||||||
|
if (req.query.key !== undefined) {
|
||||||
|
UserModel.find({key: req.query.key}).lean().exec( 'find', (err, data) => { // find user
|
||||||
|
if (err) next(err);
|
||||||
|
if (data.length === 1) { // one user found
|
||||||
|
resolve({level: data[0].level, name: data[0].name});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
16
src/index.ts
16
src/index.ts
@ -2,6 +2,8 @@ import express from 'express';
|
|||||||
import bodyParser from 'body-parser';
|
import bodyParser from 'body-parser';
|
||||||
import swagger from 'swagger-ui-express';
|
import swagger from 'swagger-ui-express';
|
||||||
import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser';
|
import jsonRefParser, {JSONSchema} from '@apidevtools/json-schema-ref-parser';
|
||||||
|
import contentFilter from 'content-filter';
|
||||||
|
import mongoSanitize from 'mongo-sanitize';
|
||||||
import db from './db';
|
import db from './db';
|
||||||
|
|
||||||
|
|
||||||
@ -23,9 +25,23 @@ const port = process.env.PORT || 3000;
|
|||||||
app.use(express.json({ limit: '5mb'}));
|
app.use(express.json({ limit: '5mb'}));
|
||||||
app.use(express.urlencoded({ extended: false, limit: '5mb' }));
|
app.use(express.urlencoded({ extended: false, limit: '5mb' }));
|
||||||
app.use(bodyParser.json());
|
app.use(bodyParser.json());
|
||||||
|
app.use(contentFilter()); // filter URL query attacks
|
||||||
|
app.use((req, res, next) => { // filter body query attacks
|
||||||
|
req.body = mongoSanitize(req.body);
|
||||||
|
next();
|
||||||
|
});
|
||||||
app.use((err, req, res, ignore) => { // bodyParser error handling
|
app.use((err, req, res, ignore) => { // bodyParser error handling
|
||||||
res.status(400).send({status: 'Invalid JSON body'});
|
res.status(400).send({status: 'Invalid JSON body'});
|
||||||
});
|
});
|
||||||
|
app.use((req, res, next) => { // no database connection error
|
||||||
|
if (db.getState().db) {
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res.status(500).send({status: 'Internal server error'});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
app.use(require('./helpers/authorize')); // handle authentication
|
||||||
|
|
||||||
// require routes
|
// require routes
|
||||||
app.use('/', require('./routes/root'));
|
app.use('/', require('./routes/root'));
|
||||||
|
@ -26,14 +26,16 @@ describe('/', () => {
|
|||||||
supertest(server)
|
supertest(server)
|
||||||
.get('/')
|
.get('/')
|
||||||
.expect('Content-type', /json/)
|
.expect('Content-type', /json/)
|
||||||
.expect(200, (err, res) => {
|
.expect(200)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
should(res.body).be.eql({status: 'API server up and running!'});
|
should(res.body).be.eql({status: 'API server up and running!'});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Testing unknown routes', () => {
|
describe('Unknown routes', () => {
|
||||||
let server;
|
let server;
|
||||||
|
|
||||||
before(done => {
|
before(done => {
|
||||||
@ -50,10 +52,94 @@ describe('Testing unknown routes', () => {
|
|||||||
afterEach(done => {
|
afterEach(done => {
|
||||||
server.close(done);
|
server.close(done);
|
||||||
});
|
});
|
||||||
it('returns a 404 message', done => {
|
it('return a 404 message', done => {
|
||||||
supertest(server)
|
supertest(server)
|
||||||
.get('/unknownroute')
|
.get('/unknownroute')
|
||||||
.expect(404);
|
.expect(404)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Not found'});
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('An unauthorized request', () => {
|
||||||
|
let server;
|
||||||
|
|
||||||
|
before(done => {
|
||||||
|
db.connect('test', done);
|
||||||
|
});
|
||||||
|
beforeEach(done => {
|
||||||
|
delete require.cache[require.resolve('../index')]; // prevent loading from cache
|
||||||
|
server = require('../index');
|
||||||
|
db.drop(err => { // reset database
|
||||||
|
if (err) return done(err);
|
||||||
|
db.loadJson(require('../test/db.json'), done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterEach(done => {
|
||||||
|
server.close(done);
|
||||||
|
});
|
||||||
|
it('returns a 401 message', done => {
|
||||||
|
supertest(server)
|
||||||
|
.get('/authorized')
|
||||||
|
.expect(401)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Unauthorized'});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('does not work with correct username', done => {
|
||||||
|
supertest(server)
|
||||||
|
.get('/authorized')
|
||||||
|
.auth('admin', 'Abc123!!')
|
||||||
|
.expect(401)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Unauthorized'});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('An authorized request', () => {
|
||||||
|
let server;
|
||||||
|
|
||||||
|
before(done => {
|
||||||
|
db.connect('test', done);
|
||||||
|
});
|
||||||
|
beforeEach(done => {
|
||||||
|
delete require.cache[require.resolve('../index')]; // prevent loading from cache
|
||||||
|
server = require('../index');
|
||||||
|
db.drop(err => { // reset database
|
||||||
|
if (err) return done(err);
|
||||||
|
db.loadJson(require('../test/db.json'), done);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterEach(done => {
|
||||||
|
server.close(done);
|
||||||
|
});
|
||||||
|
it('works with an API key', done => {
|
||||||
|
supertest(server)
|
||||||
|
.get('/authorized?key=5ea131671feb9c2ee0aafc9a')
|
||||||
|
.expect(200)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Authorization successful', method: 'key'});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('works with basic auth', done => {
|
||||||
|
supertest(server)
|
||||||
|
.get('/authorized')
|
||||||
|
.auth('admin', 'Abc123!#')
|
||||||
|
.expect(200)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Authorization successful', method: 'basic'});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
@ -1,4 +1,5 @@
|
|||||||
import express from 'express';
|
import express from 'express';
|
||||||
|
import globals from '../globals';
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
@ -6,4 +7,9 @@ router.get('/', (req, res) => {
|
|||||||
res.json({status: 'API server up and running!'});
|
res.json({status: 'API server up and running!'});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
router.get('/authorized', (req, res) => {
|
||||||
|
if (!req.auth(res, globals.levels)) return;
|
||||||
|
res.json({status: 'Authorization successful', method: req.authDetails.method});
|
||||||
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
@ -26,10 +26,12 @@ describe('/user/new', () => {
|
|||||||
it('returns the added user data', done => {
|
it('returns the added user data', done => {
|
||||||
supertest(server)
|
supertest(server)
|
||||||
.post('/user/new')
|
.post('/user/new')
|
||||||
|
.auth('admin', 'Abc123!#')
|
||||||
.send({email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
.send({email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
||||||
.expect('Content-type', /json/)
|
.expect('Content-type', /json/)
|
||||||
.expect(200, (err, res) => {
|
.expect(200)
|
||||||
if (err) return done(err);
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
should(res.body).have.property('_id').be.type('string');
|
should(res.body).have.property('_id').be.type('string');
|
||||||
should(res.body).have.property('email', 'john.doe@bosch.com');
|
should(res.body).have.property('email', 'john.doe@bosch.com');
|
||||||
should(res.body).have.property('name', 'johndoe');
|
should(res.body).have.property('name', 'johndoe');
|
||||||
@ -42,9 +44,11 @@ describe('/user/new', () => {
|
|||||||
it('stores the data', done => {
|
it('stores the data', done => {
|
||||||
supertest(server)
|
supertest(server)
|
||||||
.post('/user/new')
|
.post('/user/new')
|
||||||
|
.auth('admin', 'Abc123!#')
|
||||||
.send({email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
.send({email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
||||||
.expect(200, err => {
|
.expect(200)
|
||||||
if (err) return done(err);
|
.end(err => {
|
||||||
|
if (err) done (err);
|
||||||
UserModel.find({name: 'johndoe'}).lean().exec( 'find', (err, data) => {
|
UserModel.find({name: 'johndoe'}).lean().exec( 'find', (err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
should(data).have.lengthOf(1);
|
should(data).have.lengthOf(1);
|
||||||
@ -63,9 +67,11 @@ describe('/user/new', () => {
|
|||||||
it('rejects a username already in use', done => {
|
it('rejects a username already in use', done => {
|
||||||
supertest(server)
|
supertest(server)
|
||||||
.post('/user/new')
|
.post('/user/new')
|
||||||
|
.auth('admin', 'Abc123!#')
|
||||||
.send({email: 'j.doe@bosch.com', name: 'janedoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
.send({email: 'j.doe@bosch.com', name: 'janedoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
||||||
.expect(400, (err, res) => {
|
.expect(400)
|
||||||
if (err) return done(err);
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
should(res.body).be.eql({status: 'Username already taken'});
|
should(res.body).be.eql({status: 'Username already taken'});
|
||||||
UserModel.find({name: 'janedoe'}).lean().exec( 'find', (err, data) => {
|
UserModel.find({name: 'janedoe'}).lean().exec( 'find', (err, data) => {
|
||||||
if (err) return done(err);
|
if (err) return done(err);
|
||||||
@ -73,5 +79,30 @@ describe('/user/new', () => {
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}); // TODO: authentication
|
});
|
||||||
|
it('rejects requests from non-admins', done => {
|
||||||
|
supertest(server)
|
||||||
|
.post('/user/new')
|
||||||
|
.auth('janedoe', 'Abc123!#')
|
||||||
|
.send({email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
||||||
|
.expect('Content-type', /json/)
|
||||||
|
.expect(403)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Forbidden'});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('rejects requests from an admin API key', done => {
|
||||||
|
supertest(server)
|
||||||
|
.post('/user/new?key=5ea131671feb9c2ee0aafc9a')
|
||||||
|
.send({email: 'john.doe@bosch.com', name: 'johndoe', pass: 'Abc123!#', level: 'read', location: 'Rng', device_name: 'Alpha II'})
|
||||||
|
.expect('Content-type', /json/)
|
||||||
|
.expect(401)
|
||||||
|
.end((err, res) => {
|
||||||
|
if (err) done (err);
|
||||||
|
should(res.body).be.eql({status: 'Unauthorized'});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
@ -11,6 +11,9 @@ router.get('/users', (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
router.post('/user/new', (req, res, next) => {
|
router.post('/user/new', (req, res, next) => {
|
||||||
|
console.log(req.authDetails);
|
||||||
|
if (!req.auth(res, ['admin'], 'basic')) return;
|
||||||
|
|
||||||
// validate input
|
// validate input
|
||||||
const {error, value: user} = UserValidate.input(req.body);
|
const {error, value: user} = UserValidate.input(req.body);
|
||||||
if(error !== undefined) {
|
if(error !== undefined) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import joi from '@hapi/joi';
|
import joi from '@hapi/joi';
|
||||||
import globals from "../../globals";
|
import globals from '../../globals';
|
||||||
|
|
||||||
export default class UserValidate { // validate input for user
|
export default class UserValidate { // validate input for user
|
||||||
static input (data) {
|
static input (data) {
|
||||||
@ -27,6 +27,7 @@ export default class UserValidate { // validate input for user
|
|||||||
.required(),
|
.required(),
|
||||||
|
|
||||||
device_name: joi.string()
|
device_name: joi.string()
|
||||||
|
.allow('')
|
||||||
.required()
|
.required()
|
||||||
}).validate(data);
|
}).validate(data);
|
||||||
}
|
}
|
||||||
|
@ -5,12 +5,23 @@
|
|||||||
"_id": "5ea0450ed851c30a90e70894",
|
"_id": "5ea0450ed851c30a90e70894",
|
||||||
"email": "jane.doe@bosch.com",
|
"email": "jane.doe@bosch.com",
|
||||||
"name": "janedoe",
|
"name": "janedoe",
|
||||||
"pass": "$2a$10$KDKZjCsgDXwhtKdXZ9oG2ueDuCZsRKOMSqHuBfCM/2R0V6DRns.sy",
|
"pass": "$2a$10$i872o3qR5V3JnbDArD8Z.eDo.BNPDBaR7dUX9KSEtl9pUjLyucy2K",
|
||||||
"level": "write",
|
"level": "write",
|
||||||
"location": "Rng",
|
"location": "Rng",
|
||||||
"device_name": "Alpha I",
|
"device_name": "Alpha I",
|
||||||
"key": "5ea0450ed851c30a90e70899",
|
"key": "5ea0450ed851c30a90e70899",
|
||||||
"__v": 0
|
"__v": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"_id": "5ea131671feb9c2ee0aafc9b",
|
||||||
|
"email": "a.d.m.i.n@bosch.com",
|
||||||
|
"name": "admin",
|
||||||
|
"pass": "$2a$10$i872o3qR5V3JnbDArD8Z.eDo.BNPDBaR7dUX9KSEtl9pUjLyucy2K",
|
||||||
|
"level": "admin",
|
||||||
|
"location": "Rng",
|
||||||
|
"device_name": "",
|
||||||
|
"key": "5ea131671feb9c2ee0aafc9a",
|
||||||
|
"__v": "0"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user