Merge node-fetch-cookies
This commit is contained in:
commit
31bec14cc2
15
.eslintrc.json
Normal file
15
.eslintrc.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"es2020": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
|
||||||
|
"plugins": ["prettier"],
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 11,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"prettier/prettier": "error"
|
||||||
|
}
|
||||||
|
}
|
6
.prettierrc.json
Normal file
6
.prettierrc.json
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
{
|
||||||
|
"tabWidth": 4,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"bracketSpacing": false,
|
||||||
|
"arrowParens": "avoid"
|
||||||
|
}
|
12
.travis.yml
12
.travis.yml
|
@ -4,4 +4,14 @@ node_js:
|
||||||
- lts/*
|
- lts/*
|
||||||
- 11.14.0
|
- 11.14.0
|
||||||
script:
|
script:
|
||||||
- node --experimental-modules test/index.mjs
|
- npm test
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
provider: npm
|
||||||
|
email: npm@totally.rip
|
||||||
|
api_key:
|
||||||
|
secure: 49x2b6FaWwTCfRXXl2CaQyADZ5cvWkxS/QHRjWOJaOyPVO0M/6H23EWGxu3xttUfKHv+RADrrWKiOnJhnOVD08wO/kpC3jizKQa7D3z08hLmt8lNf6I+gt3VjUnaM1JvEAtGruJcx0aUvbqEVEJ5EehPgE+4/IGCcYC0gF+xEU1ButyQprQspw333jAEBj+0EbwV3K8Tr8CdlpZHN2wh8uzSHGg1m6jMbVZcamI3uo1INoRzhGt5Fd4t5xPOfUYyFPMopCnXX8cwed5O3lgx8nFzhS7kSl8lJrCkhzrqmx/84s1mssEj6hvz6bH5zRwj9Om3wr/1N/Q76sP4Tf6kwbpMXZR/+1dUCgbdSV7XGqaUSDzsuOPUW9+cC/RBF0O0Cr/EfmvJx4Uy5pW/OcCAYBmmMxaupEkW583oGm3lTe66UW9x866j5HyG/z2ElsEDBJscpB2niB4pa71g+ypiJcWydruozOiejS+/Edy/cfM/JPmJv1BTpr8IntWKKsriVcrLXo1p+RMRAS1ZJzg+bU0wuBWTK4EbLE8663VBg4oTd9E1pwvpt5pnFKopeYtVLDX0Vtvd4+XQaUMf80Dx6mLrS1hWyLrt+fe1LX+1gNhwZFLDM0FZnnAaszzxVBAJlpD3F4hz7Jb6Q2ZRvNWP8DCNcJPtlcimSb8usk1eTDE=
|
||||||
|
on:
|
||||||
|
branch: master
|
||||||
|
tags: true
|
||||||
|
repo: jkhsjdhjs/node-fetch-cookies
|
||||||
|
|
50
README.md
50
README.md
|
@ -4,9 +4,10 @@ It supports reading/writing from/to a JSON cookie jar and keeps cookies in memor
|
||||||
|
|
||||||
### For upgrading from 1.2.x or below to 1.3.x or above, please read the [breaking API changes](#130-breaking-api-changes).
|
### For upgrading from 1.2.x or below to 1.3.x or above, please read the [breaking API changes](#130-breaking-api-changes).
|
||||||
|
|
||||||
|
|
||||||
## Usage Examples
|
## Usage Examples
|
||||||
|
|
||||||
### with file...
|
### with file...
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import {fetch, CookieJar} from "flumm-fetch-cookies";
|
import {fetch, CookieJar} from "flumm-fetch-cookies";
|
||||||
|
|
||||||
|
@ -26,6 +27,7 @@ import {fetch, CookieJar} from "flumm-fetch-cookies";
|
||||||
```
|
```
|
||||||
|
|
||||||
### ...or without
|
### ...or without
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import {fetch, CookieJar} from "node-fetch-cookies";
|
import {fetch, CookieJar} from "node-fetch-cookies";
|
||||||
|
|
||||||
|
@ -39,31 +41,37 @@ import {fetch, CookieJar} from "node-fetch-cookies";
|
||||||
});
|
});
|
||||||
|
|
||||||
// do some requests you require login for
|
// do some requests you require login for
|
||||||
response = await fetch(cookieJar, "https://example.com/api/admin/drop-all-databases");
|
response = await fetch(
|
||||||
|
cookieJar,
|
||||||
|
"https://example.com/api/admin/drop-all-databases"
|
||||||
|
);
|
||||||
|
|
||||||
// and optionally log out again
|
// and optionally log out again
|
||||||
response = await fetch(cookieJar, "https://example.com/api/logout");
|
response = await fetch(cookieJar, "https://example.com/api/logout");
|
||||||
})();
|
})();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
||||||
### async fetch(cookieJars, url[, options])
|
### async fetch(cookieJars, url[, options])
|
||||||
|
|
||||||
- `cookieJars` A [CookieJar](#class-cookiejar) instance, an array of CookieJar instances or null, if you don't want to send or store cookies.
|
- `cookieJars` A [CookieJar](#class-cookiejar) instance, an array of CookieJar instances or null, if you don't want to send or store cookies.
|
||||||
- `url` and `options` as in https://github.com/bitinn/node-fetch#fetchurl-options
|
- `url` and `options` as in https://github.com/bitinn/node-fetch#fetchurl-options
|
||||||
|
|
||||||
Returns a Promise resolving to a [Response](https://github.com/bitinn/node-fetch#class-response) instance on success.
|
Returns a Promise resolving to a [Response](https://github.com/bitinn/node-fetch#class-response) instance on success.
|
||||||
|
|
||||||
### Class: CookieJar
|
### Class: CookieJar
|
||||||
|
|
||||||
A class that stores cookies.
|
A class that stores cookies.
|
||||||
|
|
||||||
#### Properties
|
#### Properties
|
||||||
|
|
||||||
- `flags` The read/write flags as specified below.
|
- `flags` The read/write flags as specified below.
|
||||||
- `file` The path of the cookie jar on the disk.
|
- `file` The path of the cookie jar on the disk.
|
||||||
- `cookies` A [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) mapping hostnames to maps, which map cookie names to the respective [Cookie](#class-cookie) instance.
|
- `cookies` A [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) mapping hostnames to maps, which map cookie names to the respective [Cookie](#class-cookie) instance.
|
||||||
|
|
||||||
#### new CookieJar([file, flags = `rw`, cookies, cookieIgnoreCallback])
|
#### new CookieJar([file, flags = `rw`, cookies, cookieIgnoreCallback])
|
||||||
|
|
||||||
- `file` An optional string containing a relative or absolute path to the file on the disk to use.
|
- `file` An optional string containing a relative or absolute path to the file on the disk to use.
|
||||||
- `flags` An optional string specifying whether cookies should be read and/or written from/to the jar when passing it as parameter to [fetch](#fetchcookiejar-url-options). Default: `rw`
|
- `flags` An optional string specifying whether cookies should be read and/or written from/to the jar when passing it as parameter to [fetch](#fetchcookiejar-url-options). Default: `rw`
|
||||||
- `r`: only read from this jar
|
- `r`: only read from this jar
|
||||||
|
@ -75,7 +83,9 @@ A class that stores cookies.
|
||||||
- `reason` A string containing the reason why the cookie has been ignored
|
- `reason` A string containing the reason why the cookie has been ignored
|
||||||
|
|
||||||
#### addCookie(cookie[, fromURL])
|
#### addCookie(cookie[, fromURL])
|
||||||
|
|
||||||
Adds a cookie to the jar.
|
Adds a cookie to the jar.
|
||||||
|
|
||||||
- `cookie` A [Cookie](#class-cookie) instance to add to the cookie jar.
|
- `cookie` A [Cookie](#class-cookie) instance to add to the cookie jar.
|
||||||
Alternatively this can also be a string, for example a serialized cookie received from a website.
|
Alternatively this can also be a string, for example a serialized cookie received from a website.
|
||||||
In this case `fromURL` must be specified.
|
In this case `fromURL` must be specified.
|
||||||
|
@ -85,37 +95,51 @@ Returns `true` if the cookie has been added successfully. Returns `false` otherw
|
||||||
If the parser throws a [CookieParseError](#class-cookieparseerror) it will be caught and a warning will be printed to console.
|
If the parser throws a [CookieParseError](#class-cookieparseerror) it will be caught and a warning will be printed to console.
|
||||||
|
|
||||||
#### domains()
|
#### domains()
|
||||||
|
|
||||||
Returns an iterator over all domains currently stored cookies for.
|
Returns an iterator over all domains currently stored cookies for.
|
||||||
|
|
||||||
#### *cookiesDomain(domain)
|
#### \*cookiesDomain(domain)
|
||||||
|
|
||||||
Returns an iterator over all cookies currently stored for `domain`.
|
Returns an iterator over all cookies currently stored for `domain`.
|
||||||
|
|
||||||
#### *cookiesValid(withSession)
|
#### \*cookiesValid(withSession)
|
||||||
|
|
||||||
Returns an iterator over all valid (non-expired) cookies.
|
Returns an iterator over all valid (non-expired) cookies.
|
||||||
|
|
||||||
- `withSession`: A boolean. Iterator will include session cookies if set to `true`.
|
- `withSession`: A boolean. Iterator will include session cookies if set to `true`.
|
||||||
|
|
||||||
#### *cookiesAll()
|
#### \*cookiesAll()
|
||||||
|
|
||||||
Returns an iterator over all cookies currently stored.
|
Returns an iterator over all cookies currently stored.
|
||||||
|
|
||||||
#### *cookiesValidForRequest(requestURL)
|
#### \*cookiesValidForRequest(requestURL)
|
||||||
|
|
||||||
Returns an iterator over all cookies valid for a request to `url`.
|
Returns an iterator over all cookies valid for a request to `url`.
|
||||||
|
|
||||||
#### deleteExpired(sessionEnded)
|
#### deleteExpired(sessionEnded)
|
||||||
|
|
||||||
Removes all expired cookies from the jar.
|
Removes all expired cookies from the jar.
|
||||||
|
|
||||||
- `sessionEnded`: A boolean. Also removes session cookies if set to `true`.
|
- `sessionEnded`: A boolean. Also removes session cookies if set to `true`.
|
||||||
|
|
||||||
#### async load([file = this.file])
|
#### async load([file = this.file])
|
||||||
|
|
||||||
Reads cookies from `file` on the disk and adds the contained cookies.
|
Reads cookies from `file` on the disk and adds the contained cookies.
|
||||||
|
|
||||||
- `file`: Path to the file where the cookies should be saved. Default: `this.file`, the file that has been passed to the constructor.
|
- `file`: Path to the file where the cookies should be saved. Default: `this.file`, the file that has been passed to the constructor.
|
||||||
|
|
||||||
#### async save([file = this.file])
|
#### async save([file = this.file])
|
||||||
|
|
||||||
Saves the cookie jar to `file` on the disk. Only non-expired non-session cookies are saved.
|
Saves the cookie jar to `file` on the disk. Only non-expired non-session cookies are saved.
|
||||||
|
|
||||||
- `file`: Path to the file where the cookies should be saved. Default: `this.file`, the file that has been passed to the constructor.
|
- `file`: Path to the file where the cookies should be saved. Default: `this.file`, the file that has been passed to the constructor.
|
||||||
|
|
||||||
### Class: Cookie
|
### Class: Cookie
|
||||||
|
|
||||||
An abstract representation of a cookie.
|
An abstract representation of a cookie.
|
||||||
|
|
||||||
#### Properties
|
#### Properties
|
||||||
|
|
||||||
- `name` The identifier of the cookie.
|
- `name` The identifier of the cookie.
|
||||||
- `value` The value of the cookie.
|
- `value` The value of the cookie.
|
||||||
- `expiry` A [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object of the cookies expiry date or `null`, if the cookie expires with the session.
|
- `expiry` A [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object of the cookies expiry date or `null`, if the cookie expires with the session.
|
||||||
|
@ -125,30 +149,38 @@ An abstract representation of a cookie.
|
||||||
- `subdomains` A boolean value specifying whether the cookie should be used for requests to subdomains of `domain` or not.
|
- `subdomains` A boolean value specifying whether the cookie should be used for requests to subdomains of `domain` or not.
|
||||||
|
|
||||||
#### new Cookie(str, requestURL)
|
#### new Cookie(str, requestURL)
|
||||||
|
|
||||||
Creates a cookie instance from the string representation of a cookie as send by a webserver.
|
Creates a cookie instance from the string representation of a cookie as send by a webserver.
|
||||||
|
|
||||||
- `str` The string representation of a cookie.
|
- `str` The string representation of a cookie.
|
||||||
- `url` The url the cookie has been received from.
|
- `url` The url the cookie has been received from.
|
||||||
|
|
||||||
Will throw a `CookieParseError` if `str` couldn't be parsed.
|
Will throw a `CookieParseError` if `str` couldn't be parsed.
|
||||||
|
|
||||||
#### static fromObject(obj)
|
#### static fromObject(obj)
|
||||||
|
|
||||||
Creates a cookie instance from an already existing object with the same properties.
|
Creates a cookie instance from an already existing object with the same properties.
|
||||||
|
|
||||||
#### serialize()
|
#### serialize()
|
||||||
|
|
||||||
Serializes the cookie, transforming it to `name=value` so it can be used in requests.
|
Serializes the cookie, transforming it to `name=value` so it can be used in requests.
|
||||||
|
|
||||||
#### hasExpired(sessionEnded)
|
#### hasExpired(sessionEnded)
|
||||||
|
|
||||||
Returns whether the cookie has expired or not.
|
Returns whether the cookie has expired or not.
|
||||||
|
|
||||||
- `sessionEnded`: A boolean that specifies whether the current session has ended, meaning if set to `true`, the function will return `true` for session cookies.
|
- `sessionEnded`: A boolean that specifies whether the current session has ended, meaning if set to `true`, the function will return `true` for session cookies.
|
||||||
|
|
||||||
#### isValidForRequest(requestURL)
|
#### isValidForRequest(requestURL)
|
||||||
|
|
||||||
Returns whether the cookie is valid for a request to `url`.
|
Returns whether the cookie is valid for a request to `url`.
|
||||||
|
|
||||||
### Class: CookieParseError
|
### Class: CookieParseError
|
||||||
|
|
||||||
The Error that is thrown when the cookie parser located in the constructor of the [Cookie](#class-cookie) class is unable to parse the input.
|
The Error that is thrown when the cookie parser located in the constructor of the [Cookie](#class-cookie) class is unable to parse the input.
|
||||||
|
|
||||||
|
|
||||||
## 1.3.0 Breaking API Changes
|
## 1.3.0 Breaking API Changes
|
||||||
|
|
||||||
- `new CookieJar(flags, file, cookies)` has been changed to `new CookieJar(file, flags = "rw", cookies)`.
|
- `new CookieJar(flags, file, cookies)` has been changed to `new CookieJar(file, flags = "rw", cookies)`.
|
||||||
`new CookieJar("rw")` can now be written as `new CookieJar()`, `new CookieJar("rw", "jar.json")` can now be written as `new CookieJar("jar.json")`.
|
`new CookieJar("rw")` can now be written as `new CookieJar()`, `new CookieJar("rw", "jar.json")` can now be written as `new CookieJar("jar.json")`.
|
||||||
This change has been introduced to simplify the usage of this library, since `rw` is used for `flags` in most cases anyways.
|
This change has been introduced to simplify the usage of this library, since `rw` is used for `flags` in most cases anyways.
|
||||||
|
@ -158,6 +190,6 @@ The default value for `file` is the file passed to the constructor.
|
||||||
- `new CookieJar()` now doesn't load cookies from the specified file anymore. To do so, call `await CookieJar.load()` after creating the CookieJar.
|
- `new CookieJar()` now doesn't load cookies from the specified file anymore. To do so, call `await CookieJar.load()` after creating the CookieJar.
|
||||||
**NOTE: `CookieJar.load()` will throw an error if the cookie jar doesn't exist or doesn't contain valid JSON!**
|
**NOTE: `CookieJar.load()` will throw an error if the cookie jar doesn't exist or doesn't contain valid JSON!**
|
||||||
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
This project is licensed under the MIT license, see [LICENSE](LICENSE).
|
This project is licensed under the MIT license, see [LICENSE](LICENSE).
|
||||||
|
|
1158
package-lock.json
generated
1158
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "flumm-fetch-cookies",
|
"name": "flumm-fetch-cookies",
|
||||||
"version": "1.3.5",
|
"version": "1.4.0",
|
||||||
"description": "flumm-fetch wrapper that adds support for cookie-jars",
|
"description": "flumm-fetch wrapper that adds support for cookie-jars",
|
||||||
"main": "src/index.mjs",
|
"main": "src/index.mjs",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -10,7 +10,7 @@
|
||||||
"src/"
|
"src/"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "node test/index.mjs"
|
"test": "npx eslint --ext mjs . && npx prettier --check package.json package-lock.json .travis.yml .prettierrc.json .eslintrc.json README.md && node --experimental-modules test/index.mjs"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
@ -30,5 +30,11 @@
|
||||||
"homepage": "https://github.com/kein-Bot/flumm-fetch-cookies#readme",
|
"homepage": "https://github.com/kein-Bot/flumm-fetch-cookies#readme",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"flumm-fetch": "^1.0.1"
|
"flumm-fetch": "^1.0.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"eslint": "^7.2.0",
|
||||||
|
"eslint-config-prettier": "^6.11.0",
|
||||||
|
"eslint-plugin-prettier": "^3.1.4",
|
||||||
|
"prettier": "2.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,32 +5,43 @@ import {paramError, CookieParseError} from "./errors.mjs";
|
||||||
|
|
||||||
export default class CookieJar {
|
export default class CookieJar {
|
||||||
constructor(file, flags = "rw", cookies, cookieIgnoreCallback) {
|
constructor(file, flags = "rw", cookies, cookieIgnoreCallback) {
|
||||||
|
this.cookies = new Map();
|
||||||
|
|
||||||
if (file && typeof file !== "string")
|
if (file && typeof file !== "string")
|
||||||
throw paramError("Second", "file", "new CookieJar()", "string");
|
throw paramError("Second", "file", "new CookieJar()", "string");
|
||||||
if (typeof flags !== "string")
|
if (typeof flags !== "string")
|
||||||
throw paramError("First", "flags", "new CookieJar()", "string");
|
throw paramError("First", "flags", "new CookieJar()", "string");
|
||||||
if (Array.isArray(cookies)) {
|
if (Array.isArray(cookies)) {
|
||||||
if (!cookies.every(c => c instanceof Cookie))
|
if (!cookies.every(c => c instanceof Cookie))
|
||||||
throw paramError("Third", "cookies", "new CookieJar()", "[Cookie]");
|
throw paramError(
|
||||||
|
"Third",
|
||||||
|
"cookies",
|
||||||
|
"new CookieJar()",
|
||||||
|
"[Cookie]"
|
||||||
|
);
|
||||||
cookies.forEach(cookie => this.addCookie(cookie));
|
cookies.forEach(cookie => this.addCookie(cookie));
|
||||||
}
|
} else if (cookies instanceof Cookie) this.addCookie(cookies);
|
||||||
else if(cookies instanceof Cookie)
|
|
||||||
this.addCookie(cookies);
|
|
||||||
else if (cookies)
|
else if (cookies)
|
||||||
throw paramError("Third", "cookies", "new CookieJar()", ["[Cookie]", "Cookie"]);
|
throw paramError("Third", "cookies", "new CookieJar()", [
|
||||||
|
"[Cookie]",
|
||||||
|
"Cookie"
|
||||||
|
]);
|
||||||
if (cookieIgnoreCallback && typeof cookieIgnoreCallback !== "function")
|
if (cookieIgnoreCallback && typeof cookieIgnoreCallback !== "function")
|
||||||
throw paramError("Fourth", "cookieIgnoreCallback", "new CookieJar()", "function");
|
throw paramError(
|
||||||
|
"Fourth",
|
||||||
|
"cookieIgnoreCallback",
|
||||||
|
"new CookieJar()",
|
||||||
|
"function"
|
||||||
|
);
|
||||||
this.file = file;
|
this.file = file;
|
||||||
this.flags = flags;
|
this.flags = flags;
|
||||||
this.cookies = new Map();
|
|
||||||
this.cookieIgnoreCallback = cookieIgnoreCallback;
|
this.cookieIgnoreCallback = cookieIgnoreCallback;
|
||||||
}
|
}
|
||||||
addCookie(cookie, fromURL) {
|
addCookie(cookie, fromURL) {
|
||||||
if (typeof cookie === "string") {
|
if (typeof cookie === "string") {
|
||||||
try {
|
try {
|
||||||
cookie = new Cookie(cookie, fromURL);
|
cookie = new Cookie(cookie, fromURL);
|
||||||
}
|
} catch (error) {
|
||||||
catch(error) {
|
|
||||||
if (error instanceof CookieParseError) {
|
if (error instanceof CookieParseError) {
|
||||||
if (this.cookieIgnoreCallback)
|
if (this.cookieIgnoreCallback)
|
||||||
this.cookieIgnoreCallback(cookie, error.message);
|
this.cookieIgnoreCallback(cookie, error.message);
|
||||||
|
@ -38,9 +49,11 @@ export default class CookieJar {
|
||||||
}
|
}
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
} else if (!(cookie instanceof Cookie))
|
||||||
else if(!(cookie instanceof Cookie))
|
throw paramError("First", "cookie", "CookieJar.addCookie()", [
|
||||||
throw paramError("First", "cookie", "CookieJar.addCookie()", ["string", "Cookie"]);
|
"string",
|
||||||
|
"Cookie"
|
||||||
|
]);
|
||||||
if (!this.cookies.get(cookie.domain))
|
if (!this.cookies.get(cookie.domain))
|
||||||
this.cookies.set(cookie.domain, new Map());
|
this.cookies.set(cookie.domain, new Map());
|
||||||
this.cookies.get(cookie.domain).set(cookie.name, cookie);
|
this.cookies.get(cookie.domain).set(cookie.name, cookie);
|
||||||
|
@ -55,25 +68,24 @@ export default class CookieJar {
|
||||||
}
|
}
|
||||||
*cookiesValid(withSession) {
|
*cookiesValid(withSession) {
|
||||||
for (const cookie of this.cookiesAll())
|
for (const cookie of this.cookiesAll())
|
||||||
if(!cookie.hasExpired(!withSession))
|
if (!cookie.hasExpired(!withSession)) yield cookie;
|
||||||
yield cookie;
|
|
||||||
}
|
}
|
||||||
*cookiesAll() {
|
*cookiesAll() {
|
||||||
for(const domain of this.domains())
|
for (const domain of this.domains()) yield* this.cookiesDomain(domain);
|
||||||
yield* this.cookiesDomain(domain);
|
|
||||||
}
|
}
|
||||||
*cookiesValidForRequest(requestURL) {
|
*cookiesValidForRequest(requestURL) {
|
||||||
const namesYielded = new Set(),
|
const namesYielded = new Set(),
|
||||||
domains = url
|
domains = url
|
||||||
.parse(requestURL)
|
.parse(requestURL)
|
||||||
.hostname
|
.hostname.split(".")
|
||||||
.split(".")
|
|
||||||
.map((_, i, a) => a.slice(i).join("."))
|
.map((_, i, a) => a.slice(i).join("."))
|
||||||
.slice(0, -1);
|
.slice(0, -1);
|
||||||
for (const domain of domains) {
|
for (const domain of domains) {
|
||||||
for (const cookie of this.cookiesDomain(domain)) {
|
for (const cookie of this.cookiesDomain(domain)) {
|
||||||
if(cookie.isValidForRequest(requestURL)
|
if (
|
||||||
&& !namesYielded.has(cookie.name)) {
|
cookie.isValidForRequest(requestURL) &&
|
||||||
|
!namesYielded.has(cookie.name)
|
||||||
|
) {
|
||||||
namesYielded.add(cookie.name);
|
namesYielded.add(cookie.name);
|
||||||
yield cookie;
|
yield cookie;
|
||||||
}
|
}
|
||||||
|
@ -88,12 +100,17 @@ export default class CookieJar {
|
||||||
async load(file = this.file) {
|
async load(file = this.file) {
|
||||||
if (typeof file !== "string")
|
if (typeof file !== "string")
|
||||||
throw new Error("No file has been specified for this cookie jar!");
|
throw new Error("No file has been specified for this cookie jar!");
|
||||||
JSON.parse(await fs.readFile(file)).forEach(c => this.addCookie(Cookie.fromObject(c)));
|
JSON.parse(await fs.readFile(file)).forEach(c =>
|
||||||
|
this.addCookie(Cookie.fromObject(c))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
async save(file = this.file) {
|
async save(file = this.file) {
|
||||||
if (typeof file !== "string")
|
if (typeof file !== "string")
|
||||||
throw new Error("No file has been specified for this cookie jar!");
|
throw new Error("No file has been specified for this cookie jar!");
|
||||||
// only save cookies that haven't expired
|
// only save cookies that haven't expired
|
||||||
await fs.writeFile(this.file, JSON.stringify([...this.cookiesValid(false)]));
|
await fs.writeFile(
|
||||||
|
this.file,
|
||||||
|
JSON.stringify([...this.cookiesValid(false)])
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
142
src/cookie.mjs
142
src/cookie.mjs
|
@ -4,7 +4,10 @@ import {paramError, CookieParseError} from "./errors.mjs";
|
||||||
const validateHostname = (cookieHostname, requestHostname, subdomains) => {
|
const validateHostname = (cookieHostname, requestHostname, subdomains) => {
|
||||||
cookieHostname = cookieHostname.toLowerCase();
|
cookieHostname = cookieHostname.toLowerCase();
|
||||||
requestHostname = requestHostname.toLowerCase();
|
requestHostname = requestHostname.toLowerCase();
|
||||||
if(requestHostname === cookieHostname || (subdomains && requestHostname.endsWith("." + cookieHostname)))
|
if (
|
||||||
|
requestHostname === cookieHostname ||
|
||||||
|
(subdomains && requestHostname.endsWith("." + cookieHostname))
|
||||||
|
)
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
@ -12,10 +15,8 @@ const validateHostname = (cookieHostname, requestHostname, subdomains) => {
|
||||||
const validatePath = (cookiePath, requestPath) => {
|
const validatePath = (cookiePath, requestPath) => {
|
||||||
cookiePath = decodeURIComponent(cookiePath).toLowerCase();
|
cookiePath = decodeURIComponent(cookiePath).toLowerCase();
|
||||||
requestPath = decodeURIComponent(requestPath).toLowerCase();
|
requestPath = decodeURIComponent(requestPath).toLowerCase();
|
||||||
if(cookiePath.endsWith("/"))
|
if (cookiePath.endsWith("/")) cookiePath = cookiePath.slice(0, -1);
|
||||||
cookiePath = cookiePath.slice(0, -1);
|
if (requestPath.endsWith("/")) requestPath = requestPath.slice(0, -1);
|
||||||
if(requestPath.endsWith("/"))
|
|
||||||
requestPath = requestPath.slice(0, -1);
|
|
||||||
return (requestPath + "/").startsWith(cookiePath + "/");
|
return (requestPath + "/").startsWith(cookiePath + "/");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -41,8 +42,10 @@ export default class Cookie {
|
||||||
const splitted = str.split("; ");
|
const splitted = str.split("; ");
|
||||||
[this.name, this.value] = splitN(splitted[0], "=", 1);
|
[this.name, this.value] = splitN(splitted[0], "=", 1);
|
||||||
if (!this.name)
|
if (!this.name)
|
||||||
throw new CookieParseError("Invalid cookie name \"" + this.name + "\"!");
|
throw new CookieParseError(
|
||||||
if(this.value.startsWith("\"") && this.value.endsWith("\""))
|
'Invalid cookie name "' + this.name + '"!'
|
||||||
|
);
|
||||||
|
if (this.value.startsWith('"') && this.value.endsWith('"'))
|
||||||
this.value = this.value.slice(1, -1);
|
this.value = this.value.slice(1, -1);
|
||||||
|
|
||||||
const parsedURL = url.parse(requestURL);
|
const parsedURL = url.parse(requestURL);
|
||||||
|
@ -52,83 +55,120 @@ export default class Cookie {
|
||||||
k = k.toLowerCase();
|
k = k.toLowerCase();
|
||||||
if (v) {
|
if (v) {
|
||||||
if (k === "expires") {
|
if (k === "expires") {
|
||||||
if(this.expiry) // max-age has precedence over expires
|
if (this.expiry)
|
||||||
|
// max-age has precedence over expires
|
||||||
continue;
|
continue;
|
||||||
if(!/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2}[ -](?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ -]\d{2,4} \d{2}:\d{2}:\d{2} GMT$/.test(v)
|
if (
|
||||||
|| (this.expiry = new Date(v)).toString() === "Invalid Date"
|
!/^(?:Mon|Tue|Wed|Thu|Fri|Sat|Sun), \d{2}[ -](?:Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)[ -]\d{2,4} \d{2}:\d{2}:\d{2} GMT$/.test(
|
||||||
|| this.expiry.getTime() < 0)
|
v
|
||||||
throw new CookieParseError("Invalid value for Expires \"" + v + "\"!");
|
) ||
|
||||||
}
|
(this.expiry = new Date(v)).toString() ===
|
||||||
else if(k === "max-age") {
|
"Invalid Date" ||
|
||||||
|
this.expiry.getTime() < 0
|
||||||
|
)
|
||||||
|
throw new CookieParseError(
|
||||||
|
'Invalid value for Expires "' + v + '"!'
|
||||||
|
);
|
||||||
|
} else if (k === "max-age") {
|
||||||
const seconds = ~~+v;
|
const seconds = ~~+v;
|
||||||
if (seconds.toString() !== v)
|
if (seconds.toString() !== v)
|
||||||
throw new CookieParseError("Invalid value for Max-Age \"" + v + "\"!");
|
throw new CookieParseError(
|
||||||
|
'Invalid value for Max-Age "' + v + '"!'
|
||||||
|
);
|
||||||
this.expiry = new Date();
|
this.expiry = new Date();
|
||||||
this.expiry.setSeconds(this.expiry.getSeconds() + seconds);
|
this.expiry.setSeconds(this.expiry.getSeconds() + seconds);
|
||||||
}
|
} else if (k === "domain") {
|
||||||
else if(k === "domain") {
|
if (v.startsWith(".")) v = v.substring(1);
|
||||||
if(v.startsWith("."))
|
|
||||||
v = v.substring(1);
|
|
||||||
if (!validateHostname(parsedURL.hostname, v, true))
|
if (!validateHostname(parsedURL.hostname, v, true))
|
||||||
throw new CookieParseError("Invalid value for Domain \"" + v + "\": cookie was received from \"" + parsedURL.hostname + "\"!");
|
throw new CookieParseError(
|
||||||
|
'Invalid value for Domain "' +
|
||||||
|
v +
|
||||||
|
'": cookie was received from "' +
|
||||||
|
parsedURL.hostname +
|
||||||
|
'"!'
|
||||||
|
);
|
||||||
this.domain = v;
|
this.domain = v;
|
||||||
this.subdomains = true;
|
this.subdomains = true;
|
||||||
}
|
} else if (k === "path") this.path = v;
|
||||||
else if(k === "path")
|
else if (k === "samesite")
|
||||||
this.path = v;
|
// only relevant for cross site requests, so not for us
|
||||||
else if(k === "samesite") // only relevant for cross site requests, so not for us
|
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
throw new CookieParseError("Invalid key \"" + k + "\" with value \"" + v + "\" specified!");
|
throw new CookieParseError(
|
||||||
}
|
'Invalid key "' +
|
||||||
else {
|
k +
|
||||||
if(k === "secure")
|
'" with value "' +
|
||||||
this.secure = true;
|
v +
|
||||||
else if(k === "httponly") // only relevant for browsers
|
'" specified!'
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (k === "secure") this.secure = true;
|
||||||
|
else if (k === "httponly")
|
||||||
|
// only relevant for browsers
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
throw new CookieParseError("Invalid key \"" + k + "\" specified!");
|
throw new CookieParseError(
|
||||||
|
'Invalid key "' + k + '" specified!'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(this.name.toLowerCase().startsWith("__secure-") && (!this.secure || parsedURL.protocol !== "https:"))
|
if (
|
||||||
throw new CookieParseError("Cookie has \"__Secure-\" prefix but \"Secure\" isn't set or the cookie is not set via https!");
|
this.name.toLowerCase().startsWith("__secure-") &&
|
||||||
if(this.name.toLowerCase().startsWith("__host-") && (!this.secure || parsedURL.protocol !== "https:" || this.domain || this.path !== "/"))
|
(!this.secure || parsedURL.protocol !== "https:")
|
||||||
throw new CookieParseError("Cookie has \"__Host-\" prefix but \"Secure\" isn't set, the cookie is not set via https, \"Domain\" is set or \"Path\" is not equal to \"/\"!");
|
)
|
||||||
|
throw new CookieParseError(
|
||||||
|
'Cookie has "__Secure-" prefix but "Secure" isn\'t set or the cookie is not set via https!'
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
this.name.toLowerCase().startsWith("__host-") &&
|
||||||
|
(!this.secure ||
|
||||||
|
parsedURL.protocol !== "https:" ||
|
||||||
|
this.domain ||
|
||||||
|
this.path !== "/")
|
||||||
|
)
|
||||||
|
throw new CookieParseError(
|
||||||
|
'Cookie has "__Host-" prefix but "Secure" isn\'t set, the cookie is not set via https, "Domain" is set or "Path" is not equal to "/"!'
|
||||||
|
);
|
||||||
|
|
||||||
// assign defaults
|
// assign defaults
|
||||||
if (!this.domain) {
|
if (!this.domain) {
|
||||||
this.domain = parsedURL.hostname;
|
this.domain = parsedURL.hostname;
|
||||||
this.subdomains = false;
|
this.subdomains = false;
|
||||||
}
|
}
|
||||||
if(!this.path)
|
if (!this.path) this.path = "/";
|
||||||
this.path = "/";
|
if (!this.secure) this.secure = false;
|
||||||
if(!this.secure)
|
if (!this.expiry) this.expiry = null;
|
||||||
this.secure = false;
|
|
||||||
if(!this.expiry)
|
|
||||||
this.expiry = null;
|
|
||||||
}
|
}
|
||||||
static fromObject(obj) {
|
static fromObject(obj) {
|
||||||
let c = Object.assign(Object.create(this.prototype), obj);
|
let c = Object.assign(Object.create(this.prototype), obj);
|
||||||
if(typeof c.expiry === "string")
|
if (typeof c.expiry === "string") c.expiry = new Date(c.expiry);
|
||||||
c.expiry = new Date(c.expiry);
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
serialize() {
|
serialize() {
|
||||||
return this.name + "=" + this.value;
|
return this.name + "=" + this.value;
|
||||||
}
|
}
|
||||||
hasExpired(sessionEnded) {
|
hasExpired(sessionEnded) {
|
||||||
return sessionEnded && this.expiry === null || this.expiry && this.expiry < new Date();
|
return (
|
||||||
|
(sessionEnded && this.expiry === null) ||
|
||||||
|
(this.expiry && this.expiry < new Date())
|
||||||
|
);
|
||||||
}
|
}
|
||||||
isValidForRequest(requestURL) {
|
isValidForRequest(requestURL) {
|
||||||
if(this.hasExpired(false))
|
if (this.hasExpired(false)) return false;
|
||||||
return false;
|
|
||||||
const parsedURL = url.parse(requestURL);
|
const parsedURL = url.parse(requestURL);
|
||||||
if(parsedURL.protocol !== "http:" && parsedURL.protocol !== "https:"
|
if (
|
||||||
|| this.secure && parsedURL.protocol !== "https:"
|
(parsedURL.protocol !== "http:" &&
|
||||||
|| !validateHostname(this.domain, parsedURL.hostname, this.subdomains)
|
parsedURL.protocol !== "https:") ||
|
||||||
|| !validatePath(this.path, parsedURL.pathname))
|
(this.secure && parsedURL.protocol !== "https:") ||
|
||||||
|
!validateHostname(
|
||||||
|
this.domain,
|
||||||
|
parsedURL.hostname,
|
||||||
|
this.subdomains
|
||||||
|
) ||
|
||||||
|
!validatePath(this.path, parsedURL.pathname)
|
||||||
|
)
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -3,10 +3,15 @@ export class CookieParseError extends Error {
|
||||||
super(...args);
|
super(...args);
|
||||||
this.name = "CookieParseError";
|
this.name = "CookieParseError";
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
export function paramError(position, paramName, functionName, validTypes) {
|
export function paramError(position, paramName, functionName, validTypes) {
|
||||||
validTypes = [validTypes].flat().map(t => "\"" + t + "\"");
|
validTypes = [validTypes].flat().map(t => '"' + t + '"');
|
||||||
validTypes = validTypes.slice(0, -1).join(", ") + (validTypes.length > 1 ? " or " : "") + validTypes.slice(-1);
|
validTypes =
|
||||||
return new TypeError(`${position} parameter "${paramName}" passed to "${functionName}" is not of type ${validTypes}!`);
|
validTypes.slice(0, -1).join(", ") +
|
||||||
};
|
(validTypes.length > 1 ? " or " : "") +
|
||||||
|
validTypes.slice(-1);
|
||||||
|
return new TypeError(
|
||||||
|
`${position} parameter "${paramName}" passed to "${functionName}" is not of type ${validTypes}!`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
import _fetch from "flumm-fetch";
|
import _fetch from "flumm-fetch";
|
||||||
import CookieJar from "./cookie-jar.mjs";
|
import CookieJar from "./cookie-jar.mjs";
|
||||||
import Cookie from "./cookie.mjs";
|
import Cookie from "./cookie.mjs";
|
||||||
|
import {paramError, CookieParseError} from "./errors.mjs";
|
||||||
|
|
||||||
|
const redirectStatus = new Set([301, 302, 303, 307, 308]);
|
||||||
|
|
||||||
const cookieJar = new CookieJar();
|
const cookieJar = new CookieJar();
|
||||||
|
|
||||||
|
@ -17,6 +20,13 @@ export default async function fetch(url, options) {
|
||||||
options.headers.cookie = cookies.slice(0, -2);
|
options.headers.cookie = cookies.slice(0, -2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const wantFollow =
|
||||||
|
!options || !options.redirect || options.redirect === "follow";
|
||||||
|
if (wantFollow) {
|
||||||
|
if (!options) options = {};
|
||||||
|
options.redirect = "manual";
|
||||||
|
}
|
||||||
|
|
||||||
const result = await _fetch(url, options);
|
const result = await _fetch(url, options);
|
||||||
|
|
||||||
cookies = result.headers["set-cookie"] || [];
|
cookies = result.headers["set-cookie"] || [];
|
||||||
|
@ -25,6 +35,12 @@ export default async function fetch(url, options) {
|
||||||
// delete expired cookies after each request
|
// delete expired cookies after each request
|
||||||
cookieJar.deleteExpired(false);
|
cookieJar.deleteExpired(false);
|
||||||
|
|
||||||
|
if (wantFollow && redirectStatus.has(result.status)) {
|
||||||
|
const location = result.headers.get("Location");
|
||||||
|
options.redirect = "follow";
|
||||||
|
return fetch(cookieJars, location, options);
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
374
test/cookie.mjs
374
test/cookie.mjs
|
@ -4,196 +4,319 @@ import {CookieParseError} from "../src/errors.mjs";
|
||||||
export default Test => [
|
export default Test => [
|
||||||
new Test("new Cookie() / cookie parser", () => {
|
new Test("new Cookie() / cookie parser", () => {
|
||||||
const inputs = [
|
const inputs = [
|
||||||
[ // type error
|
[
|
||||||
|
// type error
|
||||||
123,
|
123,
|
||||||
""
|
""
|
||||||
],
|
],
|
||||||
[ // type error
|
[
|
||||||
|
// type error
|
||||||
"id=a3fWa",
|
"id=a3fWa",
|
||||||
123
|
123
|
||||||
],
|
],
|
||||||
[ // type error invalid url
|
[
|
||||||
|
// type error invalid url
|
||||||
"id=a3fWa",
|
"id=a3fWa",
|
||||||
""
|
""
|
||||||
],
|
],
|
||||||
[ // type error invalid url
|
[
|
||||||
|
// type error invalid url
|
||||||
"id=a3fWa",
|
"id=a3fWa",
|
||||||
"github.com"
|
"github.com"
|
||||||
],
|
],
|
||||||
// TODO: fix this test case, parser shouldn't allow it. it is currently ignored
|
// TODO: fix this test case, parser shouldn't allow it. it is currently ignored
|
||||||
[ // type error invalid url
|
[
|
||||||
|
// type error invalid url
|
||||||
"id=a3fWa",
|
"id=a3fWa",
|
||||||
"https:abc/abs"
|
"https:abc/abs"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid cookie name
|
[
|
||||||
|
// cookie parse error invalid cookie name
|
||||||
"",
|
"",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28: GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28: GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Onv 2015 07:28:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Onv 2015 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 20151 07:28:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 20151 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 32 Oct 2015 07:28:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 32 Oct 2015 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 25:28:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 25:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:61:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:61:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 UTC; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 UTC; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT+2; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT+2; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=San, 21 Onv 2015 07:28:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=San, 21 Onv 2015 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Expires=Wed, 31 Dec 1969 07:28:00 GMT; Secure; HttpOnly",
|
"id=a3fWa; Expires=Wed, 31 Dec 1969 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid value for expires
|
[
|
||||||
|
// cookie parse error invalid value for expires
|
||||||
"id=a3fWa; Max-Age=121252a; Secure; HttpOnly",
|
"id=a3fWa; Max-Age=121252a; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid key secur
|
[
|
||||||
|
// cookie parse error invalid key secur
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secur; HttpOnly",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secur; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error invalid key HttpOly with value 2
|
[
|
||||||
|
// cookie parse error invalid key HttpOly with value 2
|
||||||
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOly=2",
|
"id=a3fWa; Expires=Wed, 21 Oct 2015 07:28:00 GMT; Secure; HttpOly=2",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error not set via https
|
[
|
||||||
|
// cookie parse error not set via https
|
||||||
"__Secure-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly",
|
"__Secure-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"http://github.com"
|
"http://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error secure not set
|
[
|
||||||
|
// cookie parse error secure not set
|
||||||
"__Secure-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; HttpOnly",
|
"__Secure-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error secure not set
|
[
|
||||||
|
// cookie parse error secure not set
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; HttpOnly; Path=/",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; HttpOnly; Path=/",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error not set via https
|
[
|
||||||
|
// cookie parse error not set via https
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/",
|
||||||
"http://github.com"
|
"http://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error domain is set
|
[
|
||||||
|
// cookie parse error domain is set
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Domain=github.com; Path=/",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Domain=github.com; Path=/",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error path is not set
|
[
|
||||||
|
// cookie parse error path is not set
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error path is not equal to /
|
[
|
||||||
|
// cookie parse error path is not equal to /
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/lel/",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/lel/",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error domain is not a subdomain
|
[
|
||||||
|
// cookie parse error domain is not a subdomain
|
||||||
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Domain=github.com",
|
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Domain=github.com",
|
||||||
"https://gist.github.com"
|
"https://gist.github.com"
|
||||||
],
|
],
|
||||||
[ // cookie parse error domain is not a subdomain
|
[
|
||||||
|
// cookie parse error domain is not a subdomain
|
||||||
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Domain=npmjs.com",
|
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Domain=npmjs.com",
|
||||||
"https://gist.github.com"
|
"https://gist.github.com"
|
||||||
],
|
],
|
||||||
[ // success
|
[
|
||||||
|
// success
|
||||||
"__Secure-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly",
|
"__Secure-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // success
|
[
|
||||||
|
// success
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // success
|
[
|
||||||
|
// success
|
||||||
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2099 20:28:33 GMT; Secure; HttpOnly; Path=/",
|
"__Host-id=a3fWa; Expires=Wed, 21 Nov 2099 20:28:33 GMT; Secure; HttpOnly; Path=/",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // success
|
[
|
||||||
|
// success
|
||||||
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/lul/; Domain=.usercontent.github.com",
|
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; Path=/lul/; Domain=.usercontent.github.com",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // success
|
[
|
||||||
|
// success
|
||||||
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; SameSite=Strict; Path=/lul/; Domain=usercontent.github.com",
|
"id=a3fWa; Expires=Wed, 21 Nov 2015 07:28:00 GMT; Secure; HttpOnly; SameSite=Strict; Path=/lul/; Domain=usercontent.github.com",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // success max-age takes precendence over expires
|
[
|
||||||
|
// success max-age takes precendence over expires
|
||||||
"id=a3fWa; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=1000",
|
"id=a3fWa; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=1000",
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
],
|
||||||
[ // success max-age takes precendence over expires
|
[
|
||||||
"id=\"a3fWa\"; Max-Age=1000; Expires=Thu, 01 Jan 1970 00:00:00 GMT",
|
// success max-age takes precendence over expires
|
||||||
|
'id="a3fWa"; Max-Age=1000; Expires=Thu, 01 Jan 1970 00:00:00 GMT',
|
||||||
"https://github.com"
|
"https://github.com"
|
||||||
],
|
]
|
||||||
];
|
];
|
||||||
|
|
||||||
const catchErrorTest = (input, catchFnc) => {
|
const catchErrorTest = (input, catchFnc) => {
|
||||||
try {
|
try {
|
||||||
new Cookie(...input);
|
new Cookie(...input);
|
||||||
return false;
|
return false;
|
||||||
}
|
} catch (error) {
|
||||||
catch(error) {
|
|
||||||
return catchFnc(error);
|
return catchFnc(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const catchErrorTypeMessageTest = (input, type, message) => catchErrorTest(input, e => e instanceof type && e.message === message);
|
const catchErrorTypeMessageTest = (input, type, message) =>
|
||||||
|
catchErrorTest(
|
||||||
|
input,
|
||||||
|
e => e instanceof type && e.message === message
|
||||||
|
);
|
||||||
|
|
||||||
const compareCookieProps = (input, expiryFnc, properties) => {
|
const compareCookieProps = (input, expiryFnc, properties) => {
|
||||||
const cookie = new Cookie(...input);
|
const cookie = new Cookie(...input);
|
||||||
return Object.entries(properties).every(([prop, value]) => cookie[prop] === value)
|
return (
|
||||||
&& expiryFnc(cookie.expiry);
|
Object.entries(properties).every(
|
||||||
|
([prop, value]) => cookie[prop] === value
|
||||||
|
) && expiryFnc(cookie.expiry)
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
return inputs.slice(0, 3).every(input => catchErrorTest(input, e => e instanceof TypeError))
|
return (
|
||||||
|
inputs
|
||||||
|
.slice(0, 3)
|
||||||
|
.every(input =>
|
||||||
|
catchErrorTest(input, e => e instanceof TypeError)
|
||||||
|
) &&
|
||||||
// cookies[4] is the test case that is ignored for now
|
// cookies[4] is the test case that is ignored for now
|
||||||
|
|
||||||
&& catchErrorTypeMessageTest(inputs[5], CookieParseError, "Invalid cookie name \"\"!")
|
catchErrorTypeMessageTest(
|
||||||
&& catchErrorTypeMessageTest(inputs[6], CookieParseError, "Invalid value for Expires \"Wed, 21 Oct 2015 07:28: GMT\"!")
|
inputs[5],
|
||||||
&& catchErrorTypeMessageTest(inputs[7], CookieParseError, "Invalid value for Expires \"Wed, 21 Onv 2015 07:28:00 GMT\"!")
|
CookieParseError,
|
||||||
&& catchErrorTypeMessageTest(inputs[8], CookieParseError, "Invalid value for Expires \"Wed, 21 Oct 20151 07:28:00 GMT\"!")
|
'Invalid cookie name ""!'
|
||||||
&& catchErrorTypeMessageTest(inputs[9], CookieParseError, "Invalid value for Expires \"Wed, 32 Oct 2015 07:28:00 GMT\"!")
|
) &&
|
||||||
&& catchErrorTypeMessageTest(inputs[10], CookieParseError, "Invalid value for Expires \"Wed, 21 Oct 2015 25:28:00 GMT\"!")
|
catchErrorTypeMessageTest(
|
||||||
&& catchErrorTypeMessageTest(inputs[11], CookieParseError, "Invalid value for Expires \"Wed, 21 Oct 2015 07:61:00 GMT\"!")
|
inputs[6],
|
||||||
&& catchErrorTypeMessageTest(inputs[12], CookieParseError, "Invalid value for Expires \"Wed, 21 Oct 2015 07:28:00 UTC\"!")
|
CookieParseError,
|
||||||
&& catchErrorTypeMessageTest(inputs[13], CookieParseError, "Invalid value for Expires \"Wed, 21 Oct 2015 07:28:00 GMT+2\"!")
|
'Invalid value for Expires "Wed, 21 Oct 2015 07:28: GMT"!'
|
||||||
&& catchErrorTypeMessageTest(inputs[14], CookieParseError, "Invalid value for Expires \"San, 21 Onv 2015 07:28:00 GMT\"!")
|
) &&
|
||||||
&& catchErrorTypeMessageTest(inputs[15], CookieParseError, "Invalid value for Expires \"Wed, 31 Dec 1969 07:28:00 GMT\"!")
|
catchErrorTypeMessageTest(
|
||||||
&& catchErrorTypeMessageTest(inputs[16], CookieParseError, "Invalid value for Max-Age \"121252a\"!")
|
inputs[7],
|
||||||
&& catchErrorTypeMessageTest(inputs[17], CookieParseError, "Invalid key \"secur\" specified!")
|
CookieParseError,
|
||||||
&& catchErrorTypeMessageTest(inputs[18], CookieParseError, "Invalid key \"httpoly\" with value \"2\" specified!")
|
'Invalid value for Expires "Wed, 21 Onv 2015 07:28:00 GMT"!'
|
||||||
|
) &&
|
||||||
&& inputs.slice(19, 21).every(input => catchErrorTypeMessageTest(input, CookieParseError, "Cookie has \"__Secure-\" prefix but \"Secure\" isn't set or the cookie is not set via https!"))
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[8],
|
||||||
&& inputs.slice(21, 26).every(input => catchErrorTypeMessageTest(input, CookieParseError, "Cookie has \"__Host-\" prefix but \"Secure\" isn't set, the cookie is not set via https, \"Domain\" is set or \"Path\" is not equal to \"/\"!"))
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 21 Oct 20151 07:28:00 GMT"!'
|
||||||
&& catchErrorTypeMessageTest(inputs[26], CookieParseError, "Invalid value for Domain \"github.com\": cookie was received from \"gist.github.com\"!")
|
) &&
|
||||||
&& catchErrorTypeMessageTest(inputs[27], CookieParseError, "Invalid value for Domain \"npmjs.com\": cookie was received from \"gist.github.com\"!")
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[9],
|
||||||
&& compareCookieProps(
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 32 Oct 2015 07:28:00 GMT"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[10],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 21 Oct 2015 25:28:00 GMT"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[11],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 21 Oct 2015 07:61:00 GMT"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[12],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 21 Oct 2015 07:28:00 UTC"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[13],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 21 Oct 2015 07:28:00 GMT+2"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[14],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "San, 21 Onv 2015 07:28:00 GMT"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[15],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Expires "Wed, 31 Dec 1969 07:28:00 GMT"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[16],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Max-Age "121252a"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[17],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid key "secur" specified!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[18],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid key "httpoly" with value "2" specified!'
|
||||||
|
) &&
|
||||||
|
inputs
|
||||||
|
.slice(19, 21)
|
||||||
|
.every(input =>
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
input,
|
||||||
|
CookieParseError,
|
||||||
|
'Cookie has "__Secure-" prefix but "Secure" isn\'t set or the cookie is not set via https!'
|
||||||
|
)
|
||||||
|
) &&
|
||||||
|
inputs
|
||||||
|
.slice(21, 26)
|
||||||
|
.every(input =>
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
input,
|
||||||
|
CookieParseError,
|
||||||
|
'Cookie has "__Host-" prefix but "Secure" isn\'t set, the cookie is not set via https, "Domain" is set or "Path" is not equal to "/"!'
|
||||||
|
)
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[26],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Domain "github.com": cookie was received from "gist.github.com"!'
|
||||||
|
) &&
|
||||||
|
catchErrorTypeMessageTest(
|
||||||
|
inputs[27],
|
||||||
|
CookieParseError,
|
||||||
|
'Invalid value for Domain "npmjs.com": cookie was received from "gist.github.com"!'
|
||||||
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
inputs[28],
|
inputs[28],
|
||||||
exp => exp.getTime() === new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
exp =>
|
||||||
|
exp.getTime() ===
|
||||||
|
new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
||||||
{
|
{
|
||||||
name: "__Secure-id",
|
name: "__Secure-id",
|
||||||
value: "a3fWa",
|
value: "a3fWa",
|
||||||
|
@ -202,11 +325,12 @@ export default Test => [
|
||||||
subdomains: false,
|
subdomains: false,
|
||||||
path: "/"
|
path: "/"
|
||||||
}
|
}
|
||||||
)
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
&& compareCookieProps(
|
|
||||||
inputs[29],
|
inputs[29],
|
||||||
exp => exp.getTime() === new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
exp =>
|
||||||
|
exp.getTime() ===
|
||||||
|
new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
||||||
{
|
{
|
||||||
name: "__Host-id",
|
name: "__Host-id",
|
||||||
value: "a3fWa",
|
value: "a3fWa",
|
||||||
|
@ -215,11 +339,12 @@ export default Test => [
|
||||||
subdomains: false,
|
subdomains: false,
|
||||||
path: "/"
|
path: "/"
|
||||||
}
|
}
|
||||||
)
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
&& compareCookieProps(
|
|
||||||
inputs[30],
|
inputs[30],
|
||||||
exp => exp.getTime() === new Date("Wed, 21 Nov 2099 20:28:33 GMT").getTime(),
|
exp =>
|
||||||
|
exp.getTime() ===
|
||||||
|
new Date("Wed, 21 Nov 2099 20:28:33 GMT").getTime(),
|
||||||
{
|
{
|
||||||
name: "__Host-id",
|
name: "__Host-id",
|
||||||
value: "a3fWa",
|
value: "a3fWa",
|
||||||
|
@ -228,11 +353,12 @@ export default Test => [
|
||||||
subdomains: false,
|
subdomains: false,
|
||||||
path: "/"
|
path: "/"
|
||||||
}
|
}
|
||||||
)
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
&& compareCookieProps(
|
|
||||||
inputs[31],
|
inputs[31],
|
||||||
exp => exp.getTime() === new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
exp =>
|
||||||
|
exp.getTime() ===
|
||||||
|
new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
||||||
{
|
{
|
||||||
name: "id",
|
name: "id",
|
||||||
value: "a3fWa",
|
value: "a3fWa",
|
||||||
|
@ -241,11 +367,12 @@ export default Test => [
|
||||||
subdomains: true,
|
subdomains: true,
|
||||||
path: "/lul/"
|
path: "/lul/"
|
||||||
}
|
}
|
||||||
)
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
&& compareCookieProps(
|
|
||||||
inputs[32],
|
inputs[32],
|
||||||
exp => exp.getTime() === new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
exp =>
|
||||||
|
exp.getTime() ===
|
||||||
|
new Date("Wed, 21 Nov 2015 07:28:00 GMT").getTime(),
|
||||||
{
|
{
|
||||||
name: "id",
|
name: "id",
|
||||||
value: "a3fWa",
|
value: "a3fWa",
|
||||||
|
@ -254,11 +381,26 @@ export default Test => [
|
||||||
subdomains: true,
|
subdomains: true,
|
||||||
path: "/lul/"
|
path: "/lul/"
|
||||||
}
|
}
|
||||||
)
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
&& compareCookieProps(
|
|
||||||
inputs[33],
|
inputs[33],
|
||||||
exp => exp.getTime() > new Date("Thu, 01 Jan 1970 00:00:00 GMT").getTime(),
|
exp =>
|
||||||
|
exp.getTime() >
|
||||||
|
new Date("Thu, 01 Jan 1970 00:00:00 GMT").getTime(),
|
||||||
|
{
|
||||||
|
name: "id",
|
||||||
|
value: "a3fWa",
|
||||||
|
secure: false,
|
||||||
|
domain: "github.com",
|
||||||
|
subdomains: false,
|
||||||
|
path: "/"
|
||||||
|
}
|
||||||
|
) &&
|
||||||
|
compareCookieProps(
|
||||||
|
inputs[34],
|
||||||
|
exp =>
|
||||||
|
exp.getTime() >
|
||||||
|
new Date("Thu, 01 Jan 1970 00:00:00 GMT").getTime(),
|
||||||
{
|
{
|
||||||
name: "id",
|
name: "id",
|
||||||
value: "a3fWa",
|
value: "a3fWa",
|
||||||
|
@ -268,18 +410,6 @@ export default Test => [
|
||||||
path: "/"
|
path: "/"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
&& compareCookieProps(
|
|
||||||
inputs[34],
|
|
||||||
exp => exp.getTime() > new Date("Thu, 01 Jan 1970 00:00:00 GMT").getTime(),
|
|
||||||
{
|
|
||||||
name: "id",
|
|
||||||
value: "a3fWa",
|
|
||||||
secure: false,
|
|
||||||
domain: "github.com",
|
|
||||||
subdomains: false,
|
|
||||||
path: "/"
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
new Test("static Cookie.fromObject()", () => {
|
new Test("static Cookie.fromObject()", () => {
|
||||||
|
@ -307,24 +437,34 @@ export default Test => [
|
||||||
|
|
||||||
const cookies = inputs.map(i => Cookie.fromObject(i));
|
const cookies = inputs.map(i => Cookie.fromObject(i));
|
||||||
|
|
||||||
return cookies[0].name === "testname"
|
return (
|
||||||
&& cookies[0].value === "somevalue"
|
cookies[0].name === "testname" &&
|
||||||
&& cookies[0].domain === "github.com"
|
cookies[0].value === "somevalue" &&
|
||||||
&& cookies[0].path === "/"
|
cookies[0].domain === "github.com" &&
|
||||||
&& cookies[0].expiry.getTime() === new Date(inputs[0].expiry).getTime()
|
cookies[0].path === "/" &&
|
||||||
&& cookies[0].secure === false
|
cookies[0].expiry.getTime() ===
|
||||||
&& cookies[0].subdomains === false
|
new Date(inputs[0].expiry).getTime() &&
|
||||||
|
cookies[0].secure === false &&
|
||||||
&& cookies[1].name === "testname"
|
cookies[0].subdomains === false &&
|
||||||
&& cookies[1].value === "lul"
|
cookies[1].name === "testname" &&
|
||||||
&& cookies[1].domain === "somedomain.tld"
|
cookies[1].value === "lul" &&
|
||||||
&& cookies[1].path === "/lel/"
|
cookies[1].domain === "somedomain.tld" &&
|
||||||
&& cookies[1].expiry.getTime() === date.getTime()
|
cookies[1].path === "/lel/" &&
|
||||||
&& cookies[1].secure === true
|
cookies[1].expiry.getTime() === date.getTime() &&
|
||||||
&& cookies[1].subdomains === true;
|
cookies[1].secure === true &&
|
||||||
|
cookies[1].subdomains === true
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
new Test("Cookie.serialize()", () => {
|
new Test("Cookie.serialize()", () => {
|
||||||
return new Cookie("abc=def; Expires=Wed, 20 Oct 2018 08:08:08 GMT; Path=/", "https://somedomain.tld").serialize() === "abc=def"
|
return (
|
||||||
&& new Cookie("jkhsd231=ajkshdgi", "https://somedomain.tld").serialize() === "jkhsd231=ajkshdgi";
|
new Cookie(
|
||||||
|
"abc=def; Expires=Wed, 20 Oct 2018 08:08:08 GMT; Path=/",
|
||||||
|
"https://somedomain.tld"
|
||||||
|
).serialize() === "abc=def" &&
|
||||||
|
new Cookie(
|
||||||
|
"jkhsd231=ajkshdgi",
|
||||||
|
"https://somedomain.tld"
|
||||||
|
).serialize() === "jkhsd231=ajkshdgi"
|
||||||
|
);
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
|
@ -8,20 +8,32 @@ export default Test => [
|
||||||
const validTypes = ["lol", "lel", "lul", "lal"];
|
const validTypes = ["lol", "lel", "lul", "lal"];
|
||||||
const errors = [
|
const errors = [
|
||||||
paramError(position, paramName, functionName, validTypes[0]),
|
paramError(position, paramName, functionName, validTypes[0]),
|
||||||
paramError(position, paramName, functionName, validTypes.slice(0, 2)),
|
paramError(
|
||||||
|
position,
|
||||||
|
paramName,
|
||||||
|
functionName,
|
||||||
|
validTypes.slice(0, 2)
|
||||||
|
),
|
||||||
paramError(position, paramName, functionName, validTypes)
|
paramError(position, paramName, functionName, validTypes)
|
||||||
];
|
];
|
||||||
return errors.every(e => e instanceof TypeError)
|
return (
|
||||||
&& errors.every(e => e.name === "TypeError")
|
errors.every(e => e instanceof TypeError) &&
|
||||||
&& errors[0].message === "something parameter \"some_param\" passed to \"some_func\" is not of type \"lol\"!"
|
errors.every(e => e.name === "TypeError") &&
|
||||||
&& errors[1].message === "something parameter \"some_param\" passed to \"some_func\" is not of type \"lol\" or \"lel\"!"
|
errors[0].message ===
|
||||||
&& errors[2].message === "something parameter \"some_param\" passed to \"some_func\" is not of type \"lol\", \"lel\", \"lul\" or \"lal\"!";
|
'something parameter "some_param" passed to "some_func" is not of type "lol"!' &&
|
||||||
|
errors[1].message ===
|
||||||
|
'something parameter "some_param" passed to "some_func" is not of type "lol" or "lel"!' &&
|
||||||
|
errors[2].message ===
|
||||||
|
'something parameter "some_param" passed to "some_func" is not of type "lol", "lel", "lul" or "lal"!'
|
||||||
|
);
|
||||||
}),
|
}),
|
||||||
new Test("class CookieParseError", () => {
|
new Test("class CookieParseError", () => {
|
||||||
const message = "this is a test error";
|
const message = "this is a test error";
|
||||||
const error = new CookieParseError(message);
|
const error = new CookieParseError(message);
|
||||||
return error instanceof CookieParseError
|
return (
|
||||||
&& error.name === "CookieParseError"
|
error instanceof CookieParseError &&
|
||||||
&& error.message === message;
|
error.name === "CookieParseError" &&
|
||||||
|
error.message === message
|
||||||
|
);
|
||||||
})
|
})
|
||||||
];
|
];
|
||||||
|
|
|
@ -3,43 +3,51 @@ import errors from "./errors.mjs";
|
||||||
|
|
||||||
class Test {
|
class Test {
|
||||||
constructor(name, fnc) {
|
constructor(name, fnc) {
|
||||||
this.name = name
|
this.name = name;
|
||||||
this.fnc = fnc
|
this.fnc = fnc;
|
||||||
}
|
}
|
||||||
async runTest() {
|
async runTest() {
|
||||||
return this.fnc();
|
return this.fnc();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const tests = [
|
const tests = [cookie, errors].flatMap(t => t(Test));
|
||||||
cookie,
|
|
||||||
errors
|
|
||||||
].flatMap(t => t(Test));
|
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
console.log("running tests...");
|
console.log("running tests...");
|
||||||
const testResults = await Promise.all(tests.map(async t => {
|
const testResults = await Promise.all(
|
||||||
|
tests.map(async t => {
|
||||||
try {
|
try {
|
||||||
t.result = await t.runTest();
|
t.result = await t.runTest();
|
||||||
if (t.result !== !!t.result) {
|
if (t.result !== !!t.result) {
|
||||||
t.result = false;
|
t.result = false;
|
||||||
console.error("test did not return a boolean: " + t.name);
|
console.error("test did not return a boolean: " + t.name);
|
||||||
}
|
}
|
||||||
}
|
} catch (error) {
|
||||||
catch(error) {
|
console.error(
|
||||||
console.error("uncaught error in test: " + t.name + "\n", error);
|
"uncaught error in test: " + t.name + "\n",
|
||||||
|
error
|
||||||
|
);
|
||||||
t.result = false;
|
t.result = false;
|
||||||
}
|
}
|
||||||
return t;
|
return t;
|
||||||
}));
|
})
|
||||||
|
);
|
||||||
testResults.forEach(t => {
|
testResults.forEach(t => {
|
||||||
if(t.result)
|
if (t.result) console.info("✔ " + t.name);
|
||||||
console.info("✔ " + t.name);
|
else console.warn("✘ " + t.name);
|
||||||
else
|
|
||||||
console.warn("✘ " + t.name);
|
|
||||||
});
|
});
|
||||||
const succeededTests = testResults.map(t => t.result).reduce((a, b) => a + b);
|
const succeededTests = testResults
|
||||||
|
.map(t => t.result)
|
||||||
|
.reduce((a, b) => a + b);
|
||||||
const success = succeededTests === testResults.length;
|
const success = succeededTests === testResults.length;
|
||||||
(success ? console.info : console.warn)((success ? "✔" : "✘") + " " + succeededTests + "/" + testResults.length + " tests successful");
|
(success ? console.info : console.warn)(
|
||||||
|
(success ? "✔" : "✘") +
|
||||||
|
" " +
|
||||||
|
succeededTests +
|
||||||
|
"/" +
|
||||||
|
testResults.length +
|
||||||
|
" tests successful"
|
||||||
|
);
|
||||||
!success && process.exit(1);
|
!success && process.exit(1);
|
||||||
})();
|
})();
|
||||||
|
|
Loading…
Reference in New Issue
Block a user