'use strict';

const THOUSAND_DAYS_MS = 1e3 * 24 * 60 * 60 * 1e3;
const TEN_MINUTES_MS = 600 * 1e3;
const MAX_COOKIE_SIZE_CHARACTERS = 4e3;
const defaultCookieConfigurer = ({
  callbackUrl,
  providerId,
  appOrigin
}) => {
  const { hostname: domain, pathname, protocol } = new URL(callbackUrl);
  const secure = protocol === "https:";
  let sameSite = "lax";
  if (new URL(appOrigin).hostname !== domain && secure) {
    sameSite = "none";
  }
  const path = pathname.endsWith(`${providerId}/handler/frame`) ? pathname.slice(0, -"/handler/frame".length) : `${pathname}/${providerId}`;
  return { domain, path, secure, sameSite };
};
class OAuthCookieManager {
  constructor(options) {
    this.options = options;
    this.cookieConfigurer = options.cookieConfigurer ?? defaultCookieConfigurer;
    this.nonceCookie = `${options.providerId}-nonce`;
    this.refreshTokenCookie = `${options.providerId}-refresh-token`;
    this.grantedScopeCookie = `${options.providerId}-granted-scope`;
  }
  cookieConfigurer;
  nonceCookie;
  refreshTokenCookie;
  grantedScopeCookie;
  getConfig(origin, pathSuffix = "") {
    const cookieConfig = this.cookieConfigurer({
      providerId: this.options.providerId,
      baseUrl: this.options.baseUrl,
      callbackUrl: this.options.callbackUrl,
      appOrigin: origin ?? this.options.defaultAppOrigin
    });
    return {
      httpOnly: true,
      sameSite: "lax",
      ...cookieConfig,
      path: cookieConfig.path + pathSuffix
    };
  }
  setNonce(res, nonce, origin) {
    this.setCookie(
      res,
      this.nonceCookie,
      nonce,
      TEN_MINUTES_MS,
      origin,
      "/handler"
    );
  }
  setRefreshToken(res, refreshToken, origin) {
    this.setCookie(
      res,
      this.refreshTokenCookie,
      refreshToken,
      THOUSAND_DAYS_MS,
      origin
    );
  }
  removeRefreshToken(res, origin) {
    this.removeCookie(res, this.refreshTokenCookie, origin);
  }
  removeGrantedScopes(res, origin) {
    this.removeCookie(res, this.grantedScopeCookie, origin);
  }
  setGrantedScopes(res, scope, origin) {
    this.setCookie(
      res,
      this.grantedScopeCookie,
      scope,
      THOUSAND_DAYS_MS,
      origin
    );
  }
  getNonce(req) {
    return this.getCookie(req, this.nonceCookie);
  }
  getRefreshToken(req) {
    return this.getCookie(req, this.refreshTokenCookie);
  }
  getGrantedScopes(req) {
    return this.getCookie(req, this.grantedScopeCookie);
  }
  setCookie(res, name, val, maxAge, origin, pathSuffix = "") {
    const options = {
      maxAge,
      ...this.getConfig(origin, pathSuffix)
    };
    const req = res.req;
    let output = res;
    if (val.length > MAX_COOKIE_SIZE_CHARACTERS) {
      const nonChunkedFormatExists = !!req.cookies[name];
      if (nonChunkedFormatExists) {
        output = output.cookie(name, "", this.getRemoveCookieOptions());
      }
      const chunked = this.splitCookieToChunks(val, MAX_COOKIE_SIZE_CHARACTERS);
      chunked.forEach((value, chunkNumber) => {
        output = output.cookie(
          OAuthCookieManager.getCookieChunkName(name, chunkNumber),
          value,
          options
        );
      });
      return output;
    }
    const chunkedFormatExists = OAuthCookieManager.chunkedCookieExists(
      req,
      name
    );
    if (chunkedFormatExists) {
      for (let chunkNumber = 0; ; chunkNumber++) {
        const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber);
        const exists = !!req.cookies[key];
        if (!exists) {
          break;
        }
        output = output.cookie(key, "", this.getRemoveCookieOptions());
      }
    }
    return output.cookie(name, val, options);
  }
  getCookie(req, name) {
    const isChunked = OAuthCookieManager.chunkedCookieExists(req, name);
    if (isChunked) {
      const chunks = [];
      let chunkNumber = 0;
      let chunk = req.cookies[OAuthCookieManager.getCookieChunkName(name, chunkNumber)];
      while (chunk) {
        chunks.push(chunk);
        chunkNumber++;
        chunk = req.cookies[OAuthCookieManager.getCookieChunkName(name, chunkNumber)];
      }
      return chunks.join("");
    }
    return req.cookies[name];
  }
  removeCookie(res, name, origin) {
    const req = res.req;
    const options = this.getRemoveCookieOptions(origin);
    const isChunked = OAuthCookieManager.chunkedCookieExists(req, name);
    if (isChunked) {
      const nonChunkedFormatExists = !!req.cookies[name];
      let output = nonChunkedFormatExists ? res.cookie(name, "", options) : res;
      for (let chunkNumber = 0; ; chunkNumber++) {
        const key = OAuthCookieManager.getCookieChunkName(name, chunkNumber);
        const exists = !!req.cookies[key];
        if (!exists) {
          break;
        }
        output = output.cookie(key, "", options);
      }
      return output;
    }
    return res.cookie(name, "", options);
  }
  splitCookieToChunks(val, chunkSize) {
    const numChunks = Math.ceil(val.length / chunkSize);
    const chunks = Array(numChunks);
    let offset = 0;
    for (let i = 0; i < numChunks; i++) {
      chunks[i] = val.substring(offset, offset + chunkSize);
      offset += chunkSize;
    }
    return chunks;
  }
  static chunkedCookieExists(req, name) {
    return !!req.cookies[OAuthCookieManager.getCookieChunkName(name, 0)];
  }
  static getCookieChunkName(name, chunkIndex) {
    return `${name}-${chunkIndex}`;
  }
  getRemoveCookieOptions(origin) {
    return {
      maxAge: 0,
      ...this.getConfig(origin)
    };
  }
}

exports.OAuthCookieManager = OAuthCookieManager;
//# sourceMappingURL=OAuthCookieManager.cjs.js.map
