wangzhibo
2026-05-09 53418655c061ac26f66058253f39200aced1ab1d
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
 * Copyright (c) Microsoft Corporation. All rights reserved.
 * Licensed under the MIT License.
 */
 
import {
    ClientAuthErrorCodes,
    createClientAuthError,
} from "@azure/msal-common/browser";
import { IWindowStorage } from "./IWindowStorage.js";
 
// Cookie life calculation (hours * minutes * seconds * ms)
const COOKIE_LIFE_MULTIPLIER = 24 * 60 * 60 * 1000;
 
export const SameSiteOptions = {
    Lax: "Lax",
    None: "None",
} as const;
export type SameSiteOptions =
    (typeof SameSiteOptions)[keyof typeof SameSiteOptions];
 
export class CookieStorage implements IWindowStorage<string> {
    initialize(): Promise<void> {
        return Promise.resolve();
    }
 
    getItem(key: string): string | null {
        const name = `${encodeURIComponent(key)}`;
        const cookieList = document.cookie.split(";");
        for (let i = 0; i < cookieList.length; i++) {
            const cookie = cookieList[i];
            const [key, ...rest] = decodeURIComponent(cookie).trim().split("=");
            const value = rest.join("=");
 
            if (key === name) {
                return value;
            }
        }
        return "";
    }
 
    getUserData(): string | null {
        throw createClientAuthError(ClientAuthErrorCodes.methodNotImplemented);
    }
 
    setItem(
        key: string,
        value: string,
        cookieLifeDays?: number,
        secure: boolean = true,
        sameSite: SameSiteOptions = SameSiteOptions.Lax
    ): void {
        let cookieStr = `${encodeURIComponent(key)}=${encodeURIComponent(
            value
        )};path=/;SameSite=${sameSite};`;
 
        if (cookieLifeDays) {
            const expireTime = getCookieExpirationTime(cookieLifeDays);
            cookieStr += `expires=${expireTime};`;
        }
 
        if (secure || sameSite === SameSiteOptions.None) {
            // SameSite None requires Secure flag
            cookieStr += "Secure;";
        }
 
        document.cookie = cookieStr;
    }
 
    async setUserData(): Promise<void> {
        return Promise.reject(
            createClientAuthError(ClientAuthErrorCodes.methodNotImplemented)
        );
    }
 
    removeItem(key: string): void {
        // Setting expiration to -1 removes it
        this.setItem(key, "", -1);
    }
 
    getKeys(): string[] {
        const cookieList = document.cookie.split(";");
        const keys: Array<string> = [];
        cookieList.forEach((cookie) => {
            const cookieParts = decodeURIComponent(cookie).trim().split("=");
            keys.push(cookieParts[0]);
        });
 
        return keys;
    }
 
    containsKey(key: string): boolean {
        return this.getKeys().includes(key);
    }
 
    decryptData(): Promise<object | null> {
        // Cookie storage does not support encryption, so this method is a no-op
        return Promise.resolve(null);
    }
}
 
/**
 * Get cookie expiration time
 * @param cookieLifeDays
 */
export function getCookieExpirationTime(cookieLifeDays: number): string {
    const today = new Date();
    const expr = new Date(
        today.getTime() + cookieLifeDays * COOKIE_LIFE_MULTIPLIER
    );
    return expr.toUTCString();
}