All files / src/sso/schm SCHMWithCookies.ts

95.56% Statements 43/45
78.95% Branches 15/19
100% Functions 8/8
95.24% Lines 40/42

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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  1x   1x 1x       1x   1x 1x             3x 3x   1x 8x 8x 8x 8x   4x 4x   4x         8x 4x   8x     1x 2x 2x     1x 2x 2x     1x 2x 2x     2x     1x 6x 6x 6x     1x 4x 4x     4x                   1x 2x   1x  
import { IncomingMessage, ServerResponse } from 'http';
import dbg from 'debug';
 
import { ServerContextHandleManager } from './ServerContextHandleManager';
import { parseCookies } from '../cookies';
import { CtxtHandle } from '../..';
import { CookieToken, SSOMethod } from '../interfaces';
 
const debug = dbg('node-expose-sspi:schManager');
 
const COOKIE_KEY = 'NEGOTIATE_ID';
const COOKIE_PREFIX_VALUE = 'NEGOTIATE_';
 
interface ContextInfo {
  serverContextHandle?: CtxtHandle;
  method?: SSOMethod;
}
 
export class SCHMWithCookies extends ServerContextHandleManager {
  private sessionMap = new Map<string, ContextInfo>();
 
  getCookieToken(req: IncomingMessage, res: ServerResponse): CookieToken {
    super.getCookieToken(req, res);
    debug('initCookie');
    let cookieToken = parseCookies(req)[COOKIE_KEY];
    if (!cookieToken) {
      // generate new cookie
      debug('cookie not found, so generating one');
      cookieToken = COOKIE_PREFIX_VALUE + Math.floor(1e10 * Math.random());
      // create a long lifetime cookie
      res.setHeader(
        'Set-Cookie',
        `${COOKIE_KEY}=${cookieToken}; Max-Age=999999999`
      );
    }
    if (!this.sessionMap.has(cookieToken)) {
      this.sessionMap.set(cookieToken, {});
    }
    return cookieToken;
  }
 
  waitForReleased(cookieToken: CookieToken): Promise<void> {
    debug('wait for release with cookie', cookieToken);
    return Promise.resolve();
  }
 
  getMethod(cookieToken: CookieToken): SSOMethod {
    const contextInfo = this.sessionMap.get(cookieToken);
    return contextInfo?.method;
  }
 
  setMethod(ssoMethod: SSOMethod, cookieToken: CookieToken): void {
    const contextInfo = this.sessionMap.get(cookieToken);
    Iif (!contextInfo) {
      return;
    }
    contextInfo.method = ssoMethod;
  }
 
  getHandle(cookieToken: CookieToken): CtxtHandle | undefined {
    debug('cookieToken: ', cookieToken);
    const contextInfo = this.sessionMap.get(cookieToken);
    return contextInfo?.serverContextHandle;
  }
 
  setHandle(contextHandle: CtxtHandle, cookieToken: CookieToken): void {
    const contextInfo = this.sessionMap.get(cookieToken);
    Iif (!contextInfo) {
      return;
    }
    contextInfo.serverContextHandle = contextHandle;
  }
 
  /**
   * At the end of the negotiation this method MUST be called to release the context handle.
   *
   * @abstract
   * @param {CookieToken} cookieToken
   * @memberof ServerContextHandleManager
   */
  release(cookieToken: CookieToken): void {
    this.sessionMap.delete(cookieToken);
  }
}