This commit is contained in:
Andris Reinman 2020-09-25 12:58:00 +03:00
parent 8dfa8f4880
commit 89dad94ae3
10 changed files with 1823 additions and 270 deletions

View file

@ -82,6 +82,13 @@
"delete:any": ["*"]
},
"domainaccess": {
"create:any": ["*"],
"read:any": ["*"],
"update:any": ["*"],
"delete:any": ["*"]
},
"domainaliases": {
"create:any": ["*"],
"read:any": ["*"],
@ -145,6 +152,13 @@
"delete:any": ["*"]
},
"domainaccess": {
"create:any": ["*"],
"read:any": ["*"],
"update:any": ["*"],
"delete:any": ["*"]
},
"domainaliases": {
"create:any": ["*"],
"read:any": ["*"],
@ -217,6 +231,13 @@
"read:any": ["*"],
"update:any": ["*"],
"delete:any": ["*"]
},
"domainaccess": {
"create:any": ["*"],
"read:any": ["*"],
"update:any": ["*"],
"delete:any": ["*"]
}
},

View file

@ -4951,6 +4951,521 @@ define({ "api": [
"filename": "lib/api/dkim.js",
"groupTitle": "DKIM"
},
{
"type": "delete",
"url": "/domainaccess/:domain",
"title": "Delete a Domain from listing",
"name": "DeleteDomainAccess",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "domain",
"description": "<p>Listed domains unique ID</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"This domain does not exist\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i -XDELETE http://localhost:8080/domainaccess/59fc66a03e54454869460e45",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "get",
"url": "/domainaccess/:tag/allow",
"title": "List whitelisted domains",
"name": "GetDomainAccessAllow",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to look for</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "Object[]",
"optional": false,
"field": "results",
"description": "<p>Domain list</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.id",
"description": "<p>Entry ID</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.domain",
"description": "<p>Whitelisted domain name</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"results\": [\n {\n \"id\": \"5a1c0ee490a34c67e266931c\",\n \"domain\": \"example.com\",\n \"action\": \"allow\"\n }\n ]\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid ID\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i http://localhost:8080/domainaccess/account_12345/allow",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "get",
"url": "/domainaccess/:tag/block",
"title": "List blacklisted domains",
"name": "GetDomainAccessBlock",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to look for</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "Object[]",
"optional": false,
"field": "results",
"description": "<p>Domain list</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.id",
"description": "<p>Entry ID</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.domain",
"description": "<p>Blacklisted domain name</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"results\": [\n {\n \"id\": \"5a1c0ee490a34c67e266931c\",\n \"domain\": \"example.com\",\n \"action\": \"block\"\n }\n ]\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid ID\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i http://localhost:8080/domainaccess/account_12345/block",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "post",
"url": "/domainaccess/:tag/allow",
"title": "Add domain to whitelist",
"name": "PostDomainAccessAllow",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to match (tags are applied to users and addresses)</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "domain",
"description": "<p>Domain name to whitelist for users/addresses that include this tag</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>ID for the created record</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"id\": \"5a1c0ee490a34c67e266931c\"\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid domain\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i -XPOST http://localhost:8080/domainaccess/account_12345/allow \\\n-H 'Content-type: application/json' \\\n-d '{\n \"domain\": \"example.com\"\n}'",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "post",
"url": "/domainaccess/:tag/block",
"title": "Add domain to blacklist",
"name": "PostDomainAccessBlock",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to match (tags are applied to users and addresses)</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "domain",
"description": "<p>Domain name to blocklist for users/addresses that include this tag</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>ID for the created record</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"id\": \"5a1c0ee490a34c67e266931c\"\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid domain\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i -XPOST http://localhost:8080/domainaccess/account_12345/block \\\n-H 'Content-type: application/json' \\\n-d '{\n \"domain\": \"example.com\"\n}'",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "delete",
"url": "/domainaliases/:alias",

View file

@ -4951,6 +4951,521 @@
"filename": "lib/api/dkim.js",
"groupTitle": "DKIM"
},
{
"type": "delete",
"url": "/domainaccess/:domain",
"title": "Delete a Domain from listing",
"name": "DeleteDomainAccess",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "domain",
"description": "<p>Listed domains unique ID</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"This domain does not exist\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i -XDELETE http://localhost:8080/domainaccess/59fc66a03e54454869460e45",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "get",
"url": "/domainaccess/:tag/allow",
"title": "List whitelisted domains",
"name": "GetDomainAccessAllow",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to look for</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "Object[]",
"optional": false,
"field": "results",
"description": "<p>Domain list</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.id",
"description": "<p>Entry ID</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.domain",
"description": "<p>Whitelisted domain name</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"results\": [\n {\n \"id\": \"5a1c0ee490a34c67e266931c\",\n \"domain\": \"example.com\",\n \"action\": \"allow\"\n }\n ]\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid ID\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i http://localhost:8080/domainaccess/account_12345/allow",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "get",
"url": "/domainaccess/:tag/block",
"title": "List blacklisted domains",
"name": "GetDomainAccessBlock",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to look for</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "Object[]",
"optional": false,
"field": "results",
"description": "<p>Domain list</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.id",
"description": "<p>Entry ID</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "results.domain",
"description": "<p>Blacklisted domain name</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"results\": [\n {\n \"id\": \"5a1c0ee490a34c67e266931c\",\n \"domain\": \"example.com\",\n \"action\": \"block\"\n }\n ]\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid ID\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i http://localhost:8080/domainaccess/account_12345/block",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "post",
"url": "/domainaccess/:tag/allow",
"title": "Add domain to whitelist",
"name": "PostDomainAccessAllow",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to match (tags are applied to users and addresses)</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "domain",
"description": "<p>Domain name to whitelist for users/addresses that include this tag</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>ID for the created record</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"id\": \"5a1c0ee490a34c67e266931c\"\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid domain\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i -XPOST http://localhost:8080/domainaccess/account_12345/allow \\\n-H 'Content-type: application/json' \\\n-d '{\n \"domain\": \"example.com\"\n}'",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "post",
"url": "/domainaccess/:tag/block",
"title": "Add domain to blacklist",
"name": "PostDomainAccessBlock",
"group": "DomainAccess",
"header": {
"fields": {
"Header": [
{
"group": "Header",
"type": "String",
"optional": false,
"field": "X-Access-Token",
"description": "<p>Optional access token if authentication is enabled</p>"
}
]
},
"examples": [
{
"title": "Header-Example:",
"content": "{\n \"X-Access-Token\": \"59fc66a03e54454869460e45\"\n}",
"type": "json"
}
]
},
"parameter": {
"fields": {
"Parameter": [
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "tag",
"description": "<p>Tag to match (tags are applied to users and addresses)</p>"
},
{
"group": "Parameter",
"type": "String",
"optional": false,
"field": "domain",
"description": "<p>Domain name to blocklist for users/addresses that include this tag</p>"
}
]
}
},
"success": {
"fields": {
"Success 200": [
{
"group": "Success 200",
"type": "Boolean",
"optional": false,
"field": "success",
"description": "<p>Indicates successful response</p>"
},
{
"group": "Success 200",
"type": "String",
"optional": false,
"field": "id",
"description": "<p>ID for the created record</p>"
}
]
},
"examples": [
{
"title": "Success-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"success\": true,\n \"id\": \"5a1c0ee490a34c67e266931c\"\n}",
"type": "json"
}
]
},
"error": {
"fields": {
"Error 4xx": [
{
"group": "Error 4xx",
"optional": false,
"field": "error",
"description": "<p>Description of the error</p>"
}
]
},
"examples": [
{
"title": "Error-Response:",
"content": "HTTP/1.1 200 OK\n{\n \"error\": \"Invalid domain\"\n}",
"type": "json"
}
]
},
"examples": [
{
"title": "Example usage:",
"content": "curl -i -XPOST http://localhost:8080/domainaccess/account_12345/block \\\n-H 'Content-type: application/json' \\\n-d '{\n \"domain\": \"example.com\"\n}'",
"type": "curl"
}
],
"version": "0.0.0",
"filename": "lib/api/filters.js",
"groupTitle": "DomainAccess"
},
{
"type": "delete",
"url": "/domainaliases/:alias",

View file

@ -9,7 +9,7 @@ define({
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2020-09-17T07:32:32.508Z",
"time": "2020-09-25T08:56:50.675Z",
"url": "https://apidocjs.com",
"version": "0.25.0"
}

View file

@ -9,7 +9,7 @@
"apidoc": "0.3.0",
"generator": {
"name": "apidoc",
"time": "2020-09-17T07:32:32.508Z",
"time": "2020-09-25T08:56:50.675Z",
"url": "https://apidocjs.com",
"version": "0.25.0"
}

View file

@ -181,6 +181,16 @@ indexes:
key:
user: 1
# Indexes for the allow/block list collection
- collection: domainaccess
index:
name: by_tag
key:
tagview: 1
action: 1
domain: 1
# Indexes for the autoreply collection
- collection: autoreplies

View file

@ -1053,6 +1053,411 @@ module.exports = (db, server) => {
return next();
})
);
/**
* @api {post} /domainaccess/:tag/allow Add domain to whitelist
* @apiName PostDomainAccessAllow
* @apiGroup DomainAccess
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} tag Tag to match (tags are applied to users and addresses)
* @apiParam {String} domain Domain name to whitelist for users/addresses that include this tag
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {String} id ID for the created record
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i -XPOST http://localhost:8080/domainaccess/account_12345/allow \
* -H 'Content-type: application/json' \
* -d '{
* "domain": "example.com"
* }'
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "id": "5a1c0ee490a34c67e266931c"
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "Invalid domain"
* }
*/
/**
* @api {post} /domainaccess/:tag/block Add domain to blacklist
* @apiName PostDomainAccessBlock
* @apiGroup DomainAccess
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} tag Tag to match (tags are applied to users and addresses)
* @apiParam {String} domain Domain name to blocklist for users/addresses that include this tag
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {String} id ID for the created record
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i -XPOST http://localhost:8080/domainaccess/account_12345/block \
* -H 'Content-type: application/json' \
* -d '{
* "domain": "example.com"
* }'
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "id": "5a1c0ee490a34c67e266931c"
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "Invalid domain"
* }
*/
server.post(
'/domainaccess/:tag/:action',
tools.asyncifyJson(async (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
tag: Joi.string().trim().max(128).required(),
domain: Joi.string()
.max(255)
//.hostname()
.required(),
action: Joi.string().valid('allow', 'block').required(),
sess: sessSchema,
ip: sessIPSchema
});
const result = schema.validate(req.params, {
abortEarly: false,
convert: true
});
if (result.error) {
res.status(400);
res.json({
error: result.error.message,
code: 'InputValidationError',
details: tools.validationErrors(result)
});
return next();
}
// permissions check
req.validate(roles.can(req.role).createAny('domainaccess'));
let domain = tools.normalizeDomain(result.value.domain);
let tag = result.value.tag;
let tagview = tag.toLowerCase();
let action = result.value.action;
let r;
try {
r = await db.database.collection('domainaccess').findOneAndUpdate(
{
tagview,
domain
},
{
$setOnInsert: {
tag,
tagview,
domain
},
$set: {
action
}
},
{
upsert: true,
projection: { _id: true },
returnOriginal: false
}
);
} catch (err) {
res.json({
error: 'MongoDB Error: ' + err.message,
code: 'InternalDatabaseError'
});
return next();
}
res.json({
success: !!(r && r.value),
id: r && r.value && r.value._id
});
return next();
})
);
/**
* @api {get} /domainaccess/:tag/allow List whitelisted domains
* @apiName GetDomainAccessAllow
* @apiGroup DomainAccess
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} tag Tag to look for
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {Object[]} results Domain list
* @apiSuccess {String} results.id Entry ID
* @apiSuccess {String} results.domain Whitelisted domain name
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i http://localhost:8080/domainaccess/account_12345/allow
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "results": [
* {
* "id": "5a1c0ee490a34c67e266931c",
* "domain": "example.com",
* "action": "allow"
* }
* ]
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "Invalid ID"
* }
*/
/**
* @api {get} /domainaccess/:tag/block List blacklisted domains
* @apiName GetDomainAccessBlock
* @apiGroup DomainAccess
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} tag Tag to look for
*
* @apiSuccess {Boolean} success Indicates successful response
* @apiSuccess {Object[]} results Domain list
* @apiSuccess {String} results.id Entry ID
* @apiSuccess {String} results.domain Blacklisted domain name
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i http://localhost:8080/domainaccess/account_12345/block
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true,
* "results": [
* {
* "id": "5a1c0ee490a34c67e266931c",
* "domain": "example.com",
* "action": "block"
* }
* ]
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "Invalid ID"
* }
*/
server.get(
'/domainaccess/:tag/:action',
tools.asyncifyJson(async (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
tag: Joi.string().trim().max(128).required(),
action: Joi.string().valid('allow', 'block').required(),
sess: sessSchema,
ip: sessIPSchema
});
const result = schema.validate(req.params, {
abortEarly: false,
convert: true
});
if (result.error) {
res.status(400);
res.json({
error: result.error.message,
code: 'InputValidationError',
details: tools.validationErrors(result)
});
return next();
}
// permissions check
req.validate(roles.can(req.role).readAny('domainaccess'));
let tag = result.value.tag;
let tagview = tag.toLowerCase();
let action = result.value.action;
let domains;
try {
domains = await db.database
.collection('domainaccess')
.find({
tagview,
action
})
.sort({
domain: 1
})
.toArray();
} catch (err) {
res.json({
error: 'MongoDB Error: ' + err.message,
code: 'InternalDatabaseError'
});
return next();
}
if (!domains) {
domains = [];
}
res.json({
success: true,
results: domains.map(domainData => {
return {
id: domainData._id,
domain: domainData.domain,
action
};
})
});
return next();
})
);
/**
* @api {delete} /domainaccess/:domain Delete a Domain from listing
* @apiName DeleteDomainAccess
* @apiGroup DomainAccess
* @apiHeader {String} X-Access-Token Optional access token if authentication is enabled
* @apiHeaderExample {json} Header-Example:
* {
* "X-Access-Token": "59fc66a03e54454869460e45"
* }
*
* @apiParam {String} domain Listed domains unique ID
*
* @apiSuccess {Boolean} success Indicates successful response
*
* @apiError error Description of the error
*
* @apiExample {curl} Example usage:
* curl -i -XDELETE http://localhost:8080/domainaccess/59fc66a03e54454869460e45
*
* @apiSuccessExample {json} Success-Response:
* HTTP/1.1 200 OK
* {
* "success": true
* }
*
* @apiErrorExample {json} Error-Response:
* HTTP/1.1 200 OK
* {
* "error": "This domain does not exist"
* }
*/
server.del(
'/domainaccess/:domain',
tools.asyncifyJson(async (req, res, next) => {
res.charSet('utf-8');
const schema = Joi.object().keys({
domain: Joi.string().hex().lowercase().length(24).required(),
sess: sessSchema,
ip: sessIPSchema
});
const result = schema.validate(req.params, {
abortEarly: false,
convert: true
});
if (result.error) {
res.status(400);
res.json({
error: result.error.message,
code: 'InputValidationError',
details: tools.validationErrors(result)
});
return next();
}
// permissions check
req.validate(roles.can(req.role).deleteAny('domainaccess'));
let domain = new ObjectID(result.value.domain);
let r;
try {
r = await db.database.collection('domainaccess').deleteOne({
_id: domain
});
} catch (err) {
res.json({
error: 'MongoDB Error: ' + err.message,
code: 'InternalDatabaseError'
});
return next();
}
if (!r.deletedCount) {
res.status(404);
res.json({
error: 'Domain was not found',
code: 'DomainNotFound'
});
return next();
}
res.json({
success: true,
deleted: domain
});
return next();
})
);
};
function getFilterStrings(filter, mailboxes) {

View file

@ -74,7 +74,8 @@ class FilterHandler {
encryptMessages: true,
encryptForwarded: true,
pubKey: true,
spamLevel: true
spamLevel: true,
tagsview: true
};
if (collection === 'users') {
@ -182,7 +183,9 @@ class FilterHandler {
let meta = options.meta || {};
let received = [].concat((prepared.mimeTree.parsedHeader && prepared.mimeTree.parsedHeader.received) || []);
let parsedHeader = (prepared.mimeTree.parsedHeader && prepared.mimeTree.parsedHeader) || {};
let received = [].concat(parsedHeader.received || []);
if (received.length) {
let receivedData = parseReceived(received[0]);
@ -225,6 +228,39 @@ class FilterHandler {
let matchingFilters = [];
let filterActions = new Map();
// check global whitelist/blacklist before filters
if (userData.tagsview && userData.tagsview.length) {
let from = parsedHeader.from || parsedHeader.sender;
from = [].concat(from || []);
tools.decodeAddresses(from);
if (from && from.length) {
from = from[0];
let domain = tools.normalizeDomain(from.address.split('@').pop());
try {
let domainaccessData = await this.db.database.collection('domainaccess').findOne({
tag: { $in: userData.tagsview },
domain
});
if (domainaccessData) {
switch (domainaccessData.action) {
case 'block':
filterActions.set('spam', true);
matchingFilters.push(`block:${domainaccessData.tag}:${domainaccessData._id}`);
break;
case 'allow':
filterActions.set('spam', false);
matchingFilters.push(`allow:${domainaccessData.tag}:${domainaccessData._id}`);
break;
}
}
} catch (err) {
// ignore, not important
}
}
}
for (let filterData of filters) {
if (!(await checkFilter(filterData, prepared, maildata))) {
continue;

View file

@ -1,6 +1,6 @@
{
"name": "wildduck",
"version": "1.29.6",
"version": "1.30.0",
"description": "IMAP/POP3 server built with Node.js and MongoDB",
"main": "server.js",
"scripts": {
@ -28,7 +28,7 @@
"grunt-mocha-test": "0.13.3",
"grunt-shell-spawn": "0.4.0",
"grunt-wait": "0.3.0",
"imapflow": "1.0.50",
"imapflow": "1.0.51",
"mailparser": "3.0.0",
"mocha": "8.1.3",
"request": "2.88.2",

View file

@ -44,285 +44,336 @@ describe('API tests', function () {
userId = false;
});
it('should POST /domainaliases', async () => {
const response = await server
.post('/domainaliases')
.send({
alias: 'jõgeva.öö',
domain: 'example.com'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should GET /users/:user', async () => {
const response = await server.get(`/users/${userId}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(userId);
expect(response.body.name).to.equal('test user');
});
it('should PUT /users/:user', async () => {
const response = await server
.put(`/users/${userId}`)
.send({
name: 'user test'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should GET /users/:user (updated name)', async () => {
const response = await server.get(`/users/${userId}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(userId);
expect(response.body.name).to.equal('user test');
});
it('should POST /authenticate with success', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@example.com',
password: 'secretpass',
scope: 'master'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /authenticate with failure', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@example.com',
password: 'invalid',
scope: 'master'
})
.expect(403);
expect(response.body.error).to.exist;
expect(response.body.success).to.not.be.true;
});
it('should POST /authenticate using alias domain', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: 'secretpass',
scope: 'master'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /authenticate with failure using alias domain', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: 'invalid',
scope: 'master'
})
.expect(403);
expect(response.body.error).to.exist;
expect(response.body.success).to.not.be.true;
});
it('should POST /users/:user/asps to generate ASP', async () => {
const response = await server
.post(`/users/${userId}/asps`)
.send({
description: 'test',
scopes: ['imap', 'smtp'],
generateMobileconfig: true
})
.expect(200);
expect(response.body.error).to.not.exist;
expect(response.body.success).to.be.true;
expect(response.body.password).to.exist;
expect(response.body.mobileconfig).to.exist;
asp = response.body.password;
});
it('should POST /authenticate using ASP and allowed scope', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: asp,
scope: 'imap'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /authenticate with failure using ASP and master scope', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: asp,
scope: 'master'
})
.expect(403);
expect(response.body.error).to.exist;
expect(response.body.success).to.not.be.true;
});
it('should GET /users/:user/addresses', async () => {
const response = await server.get(`/users/${userId}/addresses`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(1);
expect(response.body.results[0].address).to.equal('testuser@example.com');
expect(response.body.results[0].main).to.be.true;
});
it('should POST users/:user/addresses', async () => {
const response1 = await server
.post(`/users/${userId}/addresses`)
.send({
address: 'alias1@example.com',
main: true
})
.expect(200);
expect(response1.body.success).to.be.true;
const response2 = await server
.post(`/users/${userId}/addresses`)
.send({
address: 'alias2@example.com'
})
.expect(200);
expect(response2.body.success).to.be.true;
});
it('should GET /users/:user (after email update', async () => {
const response = await server.get(`/users/${userId}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(userId);
expect(response.body.address).to.equal('alias1@example.com');
});
it('should GET /users/:user/addresses (updated listing)', async () => {
const response = await server.get(`/users/${userId}/addresses`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(3);
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
expect(response.body.results[0].address).to.equal('testuser@example.com');
expect(response.body.results[0].main).to.be.false;
expect(response.body.results[1].address).to.equal('alias1@example.com');
expect(response.body.results[1].main).to.be.true;
expect(response.body.results[2].address).to.equal('alias2@example.com');
expect(response.body.results[2].main).to.be.false;
address = response.body.results[2];
});
it('should DELETE users/:user/addresses/:address', async () => {
const response = await server.delete(`/users/${userId}/addresses/${address.id}`).expect(200);
expect(response.body.success).to.be.true;
});
it('should GET /users/:user/addresses (after DELETE)', async () => {
const response = await server.get(`/users/${userId}/addresses`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(2);
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
expect(response.body.results[0].address).to.equal('testuser@example.com');
expect(response.body.results[0].main).to.be.false;
expect(response.body.results[1].address).to.equal('alias1@example.com');
expect(response.body.results[1].main).to.be.true;
});
it('should GET /users/:user/mailboxes', async () => {
const response = await server.get(`/users/${userId}/mailboxes`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.gte(4);
inbox = response.body.results.find(result => result.path === 'INBOX');
expect(inbox).to.exist;
});
it('should PUT /users/:user/autoreply', async () => {
let r;
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: false,
name: '',
subject: '',
text: '',
html: '',
start: false,
end: false
describe('user', () => {
it('should POST /domainaliases', async () => {
const response = await server
.post('/domainaliases')
.send({
alias: 'jõgeva.öö',
domain: 'example.com'
})
.expect(200);
expect(response.body.success).to.be.true;
});
r = await server
.put(`/users/${userId}/autoreply`)
.send({
it('should GET /users/:user', async () => {
const response = await server.get(`/users/${userId}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(userId);
expect(response.body.name).to.equal('test user');
});
it('should PUT /users/:user', async () => {
const response = await server
.put(`/users/${userId}`)
.send({
name: 'user test'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should GET /users/:user (updated name)', async () => {
const response = await server.get(`/users/${userId}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(userId);
expect(response.body.name).to.equal('user test');
});
});
describe('authenticate', () => {
it('should POST /authenticate with success', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@example.com',
password: 'secretpass',
scope: 'master'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /authenticate with failure', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@example.com',
password: 'invalid',
scope: 'master'
})
.expect(403);
expect(response.body.error).to.exist;
expect(response.body.success).to.not.be.true;
});
it('should POST /authenticate using alias domain', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: 'secretpass',
scope: 'master'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /authenticate with failure using alias domain', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: 'invalid',
scope: 'master'
})
.expect(403);
expect(response.body.error).to.exist;
expect(response.body.success).to.not.be.true;
});
});
describe('asp', () => {
it('should POST /users/:user/asps to generate ASP', async () => {
const response = await server
.post(`/users/${userId}/asps`)
.send({
description: 'test',
scopes: ['imap', 'smtp'],
generateMobileconfig: true
})
.expect(200);
expect(response.body.error).to.not.exist;
expect(response.body.success).to.be.true;
expect(response.body.password).to.exist;
expect(response.body.mobileconfig).to.exist;
asp = response.body.password;
});
it('should POST /authenticate using ASP and allowed scope', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: asp,
scope: 'imap'
})
.expect(200);
expect(response.body.success).to.be.true;
});
it('should POST /authenticate with failure using ASP and master scope', async () => {
const response = await server
.post(`/authenticate`)
.send({
username: 'testuser@jõgeva.öö',
password: asp,
scope: 'master'
})
.expect(403);
expect(response.body.error).to.exist;
expect(response.body.success).to.not.be.true;
});
});
describe('addresses', () => {
it('should GET /users/:user/addresses', async () => {
const response = await server.get(`/users/${userId}/addresses`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(1);
expect(response.body.results[0].address).to.equal('testuser@example.com');
expect(response.body.results[0].main).to.be.true;
});
it('should POST users/:user/addresses', async () => {
const response1 = await server
.post(`/users/${userId}/addresses`)
.send({
address: 'alias1@example.com',
main: true
})
.expect(200);
expect(response1.body.success).to.be.true;
const response2 = await server
.post(`/users/${userId}/addresses`)
.send({
address: 'alias2@example.com'
})
.expect(200);
expect(response2.body.success).to.be.true;
});
it('should GET /users/:user (after email update)', async () => {
const response = await server.get(`/users/${userId}`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.id).to.equal(userId);
expect(response.body.address).to.equal('alias1@example.com');
});
it('should GET /users/:user/addresses (updated listing)', async () => {
const response = await server.get(`/users/${userId}/addresses`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(3);
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
expect(response.body.results[0].address).to.equal('testuser@example.com');
expect(response.body.results[0].main).to.be.false;
expect(response.body.results[1].address).to.equal('alias1@example.com');
expect(response.body.results[1].main).to.be.true;
expect(response.body.results[2].address).to.equal('alias2@example.com');
expect(response.body.results[2].main).to.be.false;
address = response.body.results[2];
});
it('should DELETE users/:user/addresses/:address', async () => {
const response = await server.delete(`/users/${userId}/addresses/${address.id}`).expect(200);
expect(response.body.success).to.be.true;
});
it('should GET /users/:user/addresses (after DELETE)', async () => {
const response = await server.get(`/users/${userId}/addresses`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(2);
response.body.results.sort((a, b) => a.id.localeCompare(b.id));
expect(response.body.results[0].address).to.equal('testuser@example.com');
expect(response.body.results[0].main).to.be.false;
expect(response.body.results[1].address).to.equal('alias1@example.com');
expect(response.body.results[1].main).to.be.true;
});
});
describe('mailboxes', () => {
it('should GET /users/:user/mailboxes', async () => {
const response = await server.get(`/users/${userId}/mailboxes`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.gte(4);
inbox = response.body.results.find(result => result.path === 'INBOX');
expect(inbox).to.exist;
});
});
describe('autoreply', () => {
it('should PUT /users/:user/autoreply', async () => {
let r;
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: false,
name: '',
subject: '',
text: '',
html: '',
start: false,
end: false
});
r = await server
.put(`/users/${userId}/autoreply`)
.send({
status: true,
name: 'AR name',
subject: 'AR subject',
text: 'Away from office until Dec.19',
start: '2017-11-15T00:00:00.000Z',
end: '2017-12-19T00:00:00.000Z'
})
.expect(200);
expect(r.body.success).to.be.true;
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: true,
name: 'AR name',
subject: 'AR subject',
text: 'Away from office until Dec.19',
html: '',
start: '2017-11-15T00:00:00.000Z',
end: '2017-12-19T00:00:00.000Z'
})
.expect(200);
expect(r.body.success).to.be.true;
});
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: true,
name: 'AR name',
subject: 'AR subject',
text: 'Away from office until Dec.19',
html: '',
start: '2017-11-15T00:00:00.000Z',
end: '2017-12-19T00:00:00.000Z'
});
r = await server
.put(`/users/${userId}/autoreply`)
.send({
name: 'AR name v2',
subject: '',
start: false
})
.expect(200);
expect(r.body.success).to.be.true;
r = await server
.put(`/users/${userId}/autoreply`)
.send({
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: true,
name: 'AR name v2',
subject: '',
start: false
})
.expect(200);
expect(r.body.success).to.be.true;
text: 'Away from office until Dec.19',
html: '',
start: false,
end: '2017-12-19T00:00:00.000Z'
});
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: true,
name: 'AR name v2',
subject: '',
text: 'Away from office until Dec.19',
html: '',
start: false,
end: '2017-12-19T00:00:00.000Z'
await server.delete(`/users/${userId}/autoreply`).expect(200);
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: false,
name: '',
subject: '',
text: '',
html: '',
start: false,
end: false
});
});
});
describe('domainaccess', () => {
let tag = 'account:123';
let domain;
it('should POST domainaccess/:tag/block', async () => {
const response1 = await server
.post(`/domainaccess/${tag}/block`)
.send({
domain: 'example.com'
})
.expect(200);
expect(response1.body.success).to.be.true;
const response2 = await server
.post(`/domainaccess/${tag}/block`)
.send({
domain: 'jõgeva.ee'
})
.expect(200);
expect(response2.body.success).to.be.true;
});
await server.delete(`/users/${userId}/autoreply`).expect(200);
r = await server.get(`/users/${userId}/autoreply`).expect(200);
expect(r.body).to.deep.equal({
success: true,
status: false,
name: '',
subject: '',
text: '',
html: '',
start: false,
end: false
it('should GET /domainaccess/:tag/block', async () => {
const response = await server.get(`/domainaccess/${tag}/block`).expect(200);
expect(response.body.success).to.be.true;
expect(response.body.results.length).to.equal(2);
expect(response.body.results[0].domain).to.equal('example.com');
expect(response.body.results[1].domain).to.equal('jõgeva.ee');
domain = response.body.results[1];
});
it('should DELETE domainaccess/:domain', async () => {
const response = await server.delete(`/domainaccess/${domain.id}`).expect(200);
expect(response.body.success).to.be.true;
});
});
});