@alicloud/cookie
Advanced tools
Comparing version 1.4.6 to 1.5.0
@@ -18,17 +18,18 @@ "use strict"; | ||
return document.cookie.split(/\s*;\s*/).reduce(function (result, v) { | ||
var _v$split = v.split('='), | ||
_v$split2 = (0, _slicedToArray2.default)(_v$split, 2), | ||
cookieName = _v$split2[0], | ||
cookieValue = _v$split2[1]; | ||
var _ref = v.split('='), | ||
_ref2 = (0, _slicedToArray2.default)(_ref, 2), | ||
cookieName = _ref2[0], | ||
cookieValue = _ref2[1]; | ||
// 原来的实现有问题,set 的时候用的是 `escape`,get 的时候用的是 `decodeURIComponent`,这在大多数情况下 | ||
// 没有问题,但,当 set 了一个中文的,就会抛错「URIError: malformed URI sequence」 | ||
// 这里做一下兼容,因为大部分情况下 `decodeURIComponent(escape(value)) === value` | ||
// 原来的实现有问题,set 的时候用的是 `escape`,get 的时候用的是 `decodeURIComponent`,这在大多数情况下没有问题, | ||
// 但,当 set 了一个中文的,就会抛错「URIError: malformed URI sequence」这里做一下兼容, | ||
// 因为大部分情况下 `decodeURIComponent(escape(value)) === value` | ||
try { | ||
result[cookieName] = decodeURIComponent(cookieValue); | ||
} catch (err) { | ||
result[cookieName] = unescape(cookieValue); | ||
result[cookieName] = unescape(cookieValue); // unescape 不会报错 | ||
} | ||
return result; | ||
}, {}); | ||
} |
@@ -12,2 +12,20 @@ "use strict"; | ||
* 设置 cookie,默认为时间为 180 天,设置 extra.days 为 0 可以保存为 session cookie | ||
* | ||
* HTTP 下,非 Iframe、Iframe 不跨域、Iframe 跨子域(跨全域都不行)成功的测试用例: | ||
* | ||
* | SameSite | Secure | Firefox | Chrome | Safari | | ||
* |--------------|-------------|---------|--------|--------| | ||
* | `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
* | Lax | `undefined` | ✅ | ✅ | ✅ | | ||
* | Strict | `undefined` | ✅ | ✅ | ✅ | | ||
* | ||
* HTTPS 下,非 Iframe、Iframe 不跨域、Iframe 跨子域、Iframe 跨全域(Safari 都不行)成功的测试用例: | ||
* | ||
* | SameSite | Secure | Firefox | Chrome | Safari | | ||
* |--------------|-------------|---------|--------|--------| | ||
* | None | `true` | ✅ | ✅ | ✅ | | ||
* | None | `false` | ✅ | ✅ | ✅ | | ||
* | ||
* 1. 若 HTTPS,则 `sameSite=None; secure=true` | ||
* 2. 若 HTTP,则 `SameSite` 和 `secure` 不设置 | ||
*/ | ||
@@ -21,4 +39,21 @@ function setCookie(name, value) { | ||
_ref$days = _ref.days, | ||
days = _ref$days === void 0 ? 180 : _ref$days; | ||
document.cookie = ["".concat(name, "=").concat(encodeURIComponent(value)), "domain=".concat(domain), "path=".concat(path), "expires=".concat((0, _getExpireDate.default)(days))].join(';'); | ||
days = _ref$days === void 0 ? 180 : _ref$days, | ||
sameSite0 = _ref.sameSite, | ||
secure0 = _ref.secure; | ||
var parts = ["".concat(name, "=").concat(encodeURIComponent(value)), "domain=".concat(domain), "path=".concat(path), "expires=".concat((0, _getExpireDate.default)(days))]; | ||
var sameSite = sameSite0; | ||
var secure = secure0; | ||
// 自动 sameSite + secure | ||
if (location.protocol === 'https:' && sameSite === undefined && secure === undefined) { | ||
sameSite = 'None'; | ||
secure = true; | ||
} | ||
if (sameSite !== undefined) { | ||
parts.push("sameSite=".concat(sameSite)); | ||
} | ||
if (secure !== undefined) { | ||
parts.push("secure=".concat(secure)); | ||
} | ||
document.cookie = parts.join('; '); | ||
} |
@@ -11,17 +11,18 @@ import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; | ||
return document.cookie.split(/\s*;\s*/).reduce(function (result, v) { | ||
var _v$split = v.split('='), | ||
_v$split2 = _slicedToArray(_v$split, 2), | ||
cookieName = _v$split2[0], | ||
cookieValue = _v$split2[1]; | ||
var _ref = v.split('='), | ||
_ref2 = _slicedToArray(_ref, 2), | ||
cookieName = _ref2[0], | ||
cookieValue = _ref2[1]; | ||
// 原来的实现有问题,set 的时候用的是 `escape`,get 的时候用的是 `decodeURIComponent`,这在大多数情况下 | ||
// 没有问题,但,当 set 了一个中文的,就会抛错「URIError: malformed URI sequence」 | ||
// 这里做一下兼容,因为大部分情况下 `decodeURIComponent(escape(value)) === value` | ||
// 原来的实现有问题,set 的时候用的是 `escape`,get 的时候用的是 `decodeURIComponent`,这在大多数情况下没有问题, | ||
// 但,当 set 了一个中文的,就会抛错「URIError: malformed URI sequence」这里做一下兼容, | ||
// 因为大部分情况下 `decodeURIComponent(escape(value)) === value` | ||
try { | ||
result[cookieName] = decodeURIComponent(cookieValue); | ||
} catch (err) { | ||
result[cookieName] = unescape(cookieValue); | ||
result[cookieName] = unescape(cookieValue); // unescape 不会报错 | ||
} | ||
return result; | ||
}, {}); | ||
} |
@@ -6,2 +6,20 @@ import getExpireDate from './get-expire-date'; | ||
* 设置 cookie,默认为时间为 180 天,设置 extra.days 为 0 可以保存为 session cookie | ||
* | ||
* HTTP 下,非 Iframe、Iframe 不跨域、Iframe 跨子域(跨全域都不行)成功的测试用例: | ||
* | ||
* | SameSite | Secure | Firefox | Chrome | Safari | | ||
* |--------------|-------------|---------|--------|--------| | ||
* | `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
* | Lax | `undefined` | ✅ | ✅ | ✅ | | ||
* | Strict | `undefined` | ✅ | ✅ | ✅ | | ||
* | ||
* HTTPS 下,非 Iframe、Iframe 不跨域、Iframe 跨子域、Iframe 跨全域(Safari 都不行)成功的测试用例: | ||
* | ||
* | SameSite | Secure | Firefox | Chrome | Safari | | ||
* |--------------|-------------|---------|--------|--------| | ||
* | None | `true` | ✅ | ✅ | ✅ | | ||
* | None | `false` | ✅ | ✅ | ✅ | | ||
* | ||
* 1. 若 HTTPS,则 `sameSite=None; secure=true` | ||
* 2. 若 HTTP,则 `SameSite` 和 `secure` 不设置 | ||
*/ | ||
@@ -15,4 +33,21 @@ export default function setCookie(name, value) { | ||
_ref$days = _ref.days, | ||
days = _ref$days === void 0 ? 180 : _ref$days; | ||
document.cookie = ["".concat(name, "=").concat(encodeURIComponent(value)), "domain=".concat(domain), "path=".concat(path), "expires=".concat(getExpireDate(days))].join(';'); | ||
days = _ref$days === void 0 ? 180 : _ref$days, | ||
sameSite0 = _ref.sameSite, | ||
secure0 = _ref.secure; | ||
var parts = ["".concat(name, "=").concat(encodeURIComponent(value)), "domain=".concat(domain), "path=".concat(path), "expires=".concat(getExpireDate(days))]; | ||
var sameSite = sameSite0; | ||
var secure = secure0; | ||
// 自动 sameSite + secure | ||
if (location.protocol === 'https:' && sameSite === undefined && secure === undefined) { | ||
sameSite = 'None'; | ||
secure = true; | ||
} | ||
if (sameSite !== undefined) { | ||
parts.push("sameSite=".concat(sameSite)); | ||
} | ||
if (secure !== undefined) { | ||
parts.push("secure=".concat(secure)); | ||
} | ||
document.cookie = parts.join('; '); | ||
} |
@@ -5,1 +5,2 @@ export { default as getAllCookies } from './util/get-all-cookies'; | ||
export { default as deleteCookie } from './util/delete-cookie'; | ||
export type { ICookieSetOptions as CookieSetOptions, ICookieDeleteOptions as CookieDeleteOptions } from './types'; |
@@ -1,9 +0,16 @@ | ||
export interface ICookieSetOptions { | ||
export interface ICookieOptions { | ||
domain?: string; | ||
path?: string; | ||
/** | ||
* https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite | ||
* | ||
* ❗️NOTE:轻易不要设置,请看 README | ||
*/ | ||
sameSite?: 'None' | 'Lax' | 'Strict'; | ||
secure?: boolean; | ||
} | ||
export interface ICookieSetOptions extends ICookieOptions { | ||
days?: number; | ||
} | ||
export interface ICookieDeleteOptions { | ||
domain?: string; | ||
path?: string; | ||
export interface ICookieDeleteOptions extends ICookieOptions { | ||
} |
import { ICookieSetOptions } from '../types'; | ||
/** | ||
* 设置 cookie,默认为时间为 180 天,设置 extra.days 为 0 可以保存为 session cookie | ||
* | ||
* HTTP 下,非 Iframe、Iframe 不跨域、Iframe 跨子域(跨全域都不行)成功的测试用例: | ||
* | ||
* | SameSite | Secure | Firefox | Chrome | Safari | | ||
* |--------------|-------------|---------|--------|--------| | ||
* | `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
* | Lax | `undefined` | ✅ | ✅ | ✅ | | ||
* | Strict | `undefined` | ✅ | ✅ | ✅ | | ||
* | ||
* HTTPS 下,非 Iframe、Iframe 不跨域、Iframe 跨子域、Iframe 跨全域(Safari 都不行)成功的测试用例: | ||
* | ||
* | SameSite | Secure | Firefox | Chrome | Safari | | ||
* |--------------|-------------|---------|--------|--------| | ||
* | None | `true` | ✅ | ✅ | ✅ | | ||
* | None | `false` | ✅ | ✅ | ✅ | | ||
* | ||
* 1. 若 HTTPS,则 `sameSite=None; secure=true` | ||
* 2. 若 HTTP,则 `SameSite` 和 `secure` 不设置 | ||
*/ | ||
export default function setCookie(name: string, value: string | number | boolean, { domain, path, days }?: ICookieSetOptions): void; | ||
export default function setCookie(name: string, value: string | number | boolean, { domain, path, days, sameSite: sameSite0, secure: secure0 }?: ICookieSetOptions): void; |
{ | ||
"name": "@alicloud/cookie", | ||
"version": "1.4.6", | ||
"version": "1.5.0", | ||
"description": "ConsoleBase Cookie", | ||
@@ -30,5 +30,6 @@ "license": "MIT", | ||
"@alicloud/demo-rc-elements": "^1.10.13", | ||
"@alicloud/ts-config": "^1.1.0", | ||
"@types/react": "^17.0.48", | ||
"react": "^17.0.2", | ||
"typescript": "^4.8.4" | ||
"typescript": "^4.9.3" | ||
}, | ||
@@ -46,3 +47,3 @@ "scripts": { | ||
}, | ||
"gitHead": "244c4bf763c1b236bef5fa2f7b9172a8cc027097" | ||
"gitHead": "e3daf0b177915f37e8beae4ecee204d8c62f9507" | ||
} |
269
README.md
@@ -52,1 +52,270 @@ # @alicloud/cookie | ||
``` | ||
## SameSite + Secure 以及 HTTPS 和 Iframe 的影响 | ||
以下条件下: | ||
* 协议 | ||
+ `http://` | ||
+ `https://` | ||
* iframe | ||
+ 无 | ||
+ 不跨域 | ||
+ 跨子域 | ||
+ 跨全域 | ||
SameSite 和 Secure 各值: | ||
* SameSite | ||
+ undefined | ||
+ Lax | ||
+ Strict | ||
+ None | ||
* Secure | ||
+ true | ||
+ false | ||
在各个浏览器: | ||
* 浏览器 | ||
+ Firefox | ||
+ Chrome | ||
+ Safari | ||
下对 set cookie 的影响。 | ||
### 测试脚本 | ||
注意,在 Iframe 下,需通过浏览器的 Console 切换到对应的 Iframe 上下文。 | ||
```javascript | ||
(() => { | ||
function setCookie(name, value, { | ||
path = '/', | ||
sameSite, | ||
secure | ||
} = {}) { | ||
const parts = [ | ||
`${name}=${encodeURIComponent(value)}`, | ||
// `domain=${domain}`, | ||
`path=${path}` | ||
]; | ||
if (sameSite !== undefined) { | ||
parts.push(`sameSite=${sameSite}`); | ||
} | ||
if (secure !== undefined) { | ||
parts.push(`secure=${secure}`); | ||
} | ||
document.cookie = parts.join('; '); | ||
} | ||
function getCookie(name) { | ||
return document.cookie.split(/\s*;\s*/).reduce((result, v) => { | ||
const [cookieName, cookieValue] = v.split('='); | ||
try { | ||
result[cookieName] = decodeURIComponent(cookieValue); | ||
} catch (err) { | ||
} | ||
return result; | ||
}, {})[name]; | ||
} | ||
const TIME = Date.now(); | ||
const ITEMS = [undefined, 'Lax', 'Strict', 'None'].reduce((result, sameSite) => { | ||
[undefined, true, false].forEach(secure => { | ||
const name = `TEST_SameSite_${sameSite}__Secure_${secure}`; | ||
const value = `${sameSite}_${secure}_${TIME}`; | ||
setCookie(name, value, { | ||
sameSite, | ||
secure | ||
}); | ||
const valueGet = getCookie(name); | ||
result.push({ | ||
name, | ||
value, | ||
valueGet, | ||
sameSite, | ||
secure, | ||
result: valueGet === value ? '✅' : '❌' | ||
}); | ||
}); | ||
return result; | ||
}, []); | ||
console.table(ITEMS, ['sameSite', 'secure', 'result']); | ||
})(); | ||
``` | ||
### HTTP 非 Iframe | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
| `undefined` | `true` | ❌ | ❌ | ❌ | | ||
| `undefined` | `false` | ❌ | ❌ | ❌ | | ||
| Lax | `undefined` | ✅ | ✅ | ✅ | | ||
| Lax | `true` | ❌ | ❌ | ❌ | | ||
| Lax | `false` | ❌ | ❌ | ❌ | | ||
| Strict | `undefined` | ✅ | ✅ | ✅ | | ||
| Strict | `true` | ❌ | ❌ | ❌ | | ||
| Strict | `false` | ❌ | ❌ | ❌ | | ||
| None | `undefined` | ❌ | ❌ | ✅ | | ||
| None | `true` | ❌ | ❌ | ❌ | | ||
| None | `false` | ❌ | ❌ | ❌ | | ||
### HTTP Iframe 不跨域 | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
| `undefined` | `true` | ❌ | ❌ | ❌ | | ||
| `undefined` | `false` | ❌ | ❌ | ❌ | | ||
| Lax | `undefined` | ✅ | ✅ | ✅ | | ||
| Lax | `true` | ❌ | ❌ | ❌ | | ||
| Lax | `false` | ❌ | ❌ | ❌ | | ||
| Strict | `undefined` | ✅ | ✅ | ✅ | | ||
| Strict | `true` | ❌ | ❌ | ❌ | | ||
| Strict | `false` | ❌ | ❌ | ❌ | | ||
| None | `undefined` | ❌ | ❌ | ✅ | | ||
| None | `true` | ❌ | ❌ | ❌ | | ||
| None | `false` | ❌ | ❌ | ❌ | | ||
### HTTP(Iframe 跨子域) | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
| `undefined` | `true` | ❌ | ❌ | ❌ | | ||
| `undefined` | `false` | ❌ | ❌ | ❌ | | ||
| Lax | `undefined` | ✅ | ✅ | ✅ | | ||
| Lax | `true` | ❌ | ❌ | ❌ | | ||
| Lax | `false` | ❌ | ❌ | ❌ | | ||
| Strict | `undefined` | ✅ | ✅ | ✅ | | ||
| Strict | `true` | ❌ | ❌ | ❌ | | ||
| Strict | `false` | ❌ | ❌ | ❌ | | ||
| None | `undefined` | ❌ | ❌ | ✅ | | ||
| None | `true` | ❌ | ❌ | ❌ | | ||
| None | `false` | ❌ | ❌ | ❌ | | ||
### HTTP(Iframe 跨全域) | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ❌ | ❌ | ❌ | | ||
| `undefined` | `true` | ❌ | ❌ | ❌ | | ||
| `undefined` | `false` | ❌ | ❌ | ❌ | | ||
| Lax | `undefined` | ❌ | ❌ | ❌ | | ||
| Lax | `true` | ❌ | ❌ | ❌ | | ||
| Lax | `false` | ❌ | ❌ | ❌ | | ||
| Strict | `undefined` | ❌ | ❌ | ❌ | | ||
| Strict | `true` | ❌ | ❌ | ❌ | | ||
| Strict | `false` | ❌ | ❌ | ❌ | | ||
| None | `undefined` | ❌ | ❌ | ❌ | | ||
| None | `true` | ❌ | ❌ | ❌ | | ||
| None | `false` | ❌ | ❌ | ❌ | | ||
### HTTPS 非 Iframe | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
| `undefined` | `true` | ✅ | ✅ | ✅ | | ||
| `undefined` | `false` | ✅ | ✅ | ✅ | | ||
| Lax | `undefined` | ✅ | ✅ | ✅ | | ||
| Lax | `true` | ✅ | ✅ | ✅ | | ||
| Lax | `false` | ✅ | ✅ | ✅ | | ||
| Strict | `undefined` | ✅ | ✅ | ✅ | | ||
| Strict | `true` | ✅ | ✅ | ✅ | | ||
| Strict | `false` | ✅ | ✅ | ✅ | | ||
| None | `undefined` | ❌ | ❌ | ✅ | | ||
| None | `true` | ✅ | ✅ | ✅ | | ||
| None | `false` | ✅ | ✅ | ✅ | | ||
### HTTPS 在 Iframe 下(不跨域) | ||
`a.com` 页面通过 Iframe 内嵌 `a.com` 页面,在内层 `a.com` 页面上进行测试。 | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
| `undefined` | `true` | ✅ | ✅ | ✅ | | ||
| `undefined` | `false` | ✅ | ✅ | ✅ | | ||
| Lax | `undefined` | ✅ | ✅ | ✅ | | ||
| Lax | `true` | ✅ | ✅ | ✅ | | ||
| Lax | `false` | ✅ | ✅ | ✅ | | ||
| Strict | `undefined` | ✅ | ✅ | ✅ | | ||
| Strict | `true` | ✅ | ✅ | ✅ | | ||
| Strict | `false` | ✅ | ✅ | ✅ | | ||
| None | `undefined` | ❌ | ❌ | ✅ | | ||
| None | `true` | ✅ | ✅ | ✅ | | ||
| None | `false` | ✅ | ✅ | ✅ | | ||
### HTTPS 在 Iframe 下(跨子域) | ||
`xx.a.com` 页面通过 Iframe 内嵌 `yy.a.com` 页面,在 `yy.a.com` 页面上进行测试。 | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ❌ | ✅ | | ||
| `undefined` | `true` | ✅ | ❌ | ✅ | | ||
| `undefined` | `false` | ✅ | ❌ | ✅ | | ||
| Lax | `undefined` | ❌ | ❌ | ✅ | | ||
| Lax | `true` | ❌ | ❌ | ✅ | | ||
| Lax | `false` | ❌ | ❌ | ✅ | | ||
| Strict | `undefined` | ❌ | ❌ | ✅ | | ||
| Strict | `true` | ❌ | ❌ | ✅ | | ||
| Strict | `false` | ❌ | ❌ | ✅ | | ||
| None | `undefined` | ❌ | ❌ | ✅ | | ||
| None | `true` | ✅ | ✅ | ✅ | | ||
| None | `false` | ✅ | ✅ | ✅ | | ||
### HTTPS 在 Iframe 下(跨全域) | ||
`a.com` 页面通过 Iframe 内嵌 `b.com` 页面,在 `b.com` 页面上进行测试。 | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ❌ | ❌ | | ||
| `undefined` | `true` | ✅ | ❌ | ❌ | | ||
| `undefined` | `false` | ✅ | ❌ | ❌ | | ||
| Lax | `undefined` | ❌ | ❌ | ❌ | | ||
| Lax | `true` | ❌ | ❌ | ❌ | | ||
| Lax | `false` | ❌ | ❌ | ❌ | | ||
| Strict | `undefined` | ❌ | ❌ | ❌ | | ||
| Strict | `true` | ❌ | ❌ | ❌ | | ||
| Strict | `false` | ❌ | ❌ | ❌ | | ||
| None | `undefined` | ❌ | ❌ | ❌ | | ||
| None | `true` | ✅ | ✅ | ❌ | | ||
| None | `false` | ✅ | ✅ | ❌ | | ||
## 总结 | ||
HTTP 下,非 Iframe、Iframe 不跨域、Iframe 跨子域(跨全域都不行)成功的测试用例: | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| `undefined` | `undefined` | ✅ | ✅ | ✅ | | ||
| Lax | `undefined` | ✅ | ✅ | ✅ | | ||
| Strict | `undefined` | ✅ | ✅ | ✅ | | ||
HTTPS 下,非 Iframe、Iframe 不跨域、Iframe 跨子域、Iframe 跨全域(Safari 都不行)成功的测试用例: | ||
| SameSite | Secure | Firefox | Chrome | Safari | | ||
|--------------|-------------|---------|--------|--------| | ||
| None | `true` | ✅ | ✅ | ✅ | | ||
| None | `false` | ✅ | ✅ | ✅ | | ||
默认逻辑: | ||
1. 若 HTTP,则 `SameSite` 和 `secure` 不设置 | ||
2. 若 HTTPS,则 `sameSite=None; secure=true`(前提是使用者不设置 `sameSite` 和 `secure`) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
27399
353
321
7
27