File: saml_timestamps.js

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (132 lines) | stat: -rw-r--r-- 4,768 bytes parent folder | download | duplicates (11)
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
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview A utility for decoding timestamps strings into JS Date objects.
 * This is needed for showing the SAML password expiry notifications.
 * Timestamps are allowed to be sent to us in a variety of formats, since SAML
 * administrators may not have the ability to convert between formats at their
 * end. This class doesn't need to be informed which format the timestamp is in,
 * since the different allowed formats don't tend to overlap in practice.
 *
 * The supported formats are NTFS filetimes, Unix time (in seconds or ms),
 * and ISO 8601.
 */

  /** @const @private {number} Maximum length of a valid timestamp. */
  const MAX_SANE_LENGTH = 30;

  /** @const @private {!Date} The earliest date considered sane. */
  const MIN_SANE_DATE = new Date('1980-01-01 UTC');

  /** @const @private {!Date} The latest date considered sane. */
  const MAX_SANE_DATE = new Date('10000-01-01 UTC');

  /** @const @private {!Date} Epoch for Windows NTFS FILETIME timestamps. */
  const NTFS_EPOCH = new Date('1601-01-01 UTC');

  /** @const @private {!RegExp} Pattern to match integers. */
  const INTEGER_PATTERN = /^-?\d+$/;

  /**
   * Pattern to match ISO 8601 dates / times. Rejects other text-based timestamp
   * formats (eg '01-02-03') since they cannot be parsed in a consistent way.
   * @const @private {!RegExp}
   */
  const ISO_8601_PATTERN = /^\d\d\d\d-\d\d-\d\d(T|$)/;

  /**
   * Decode a timestamp string that is in one of the supported formats.
   * @param {string} str A timestamp formatted as a string.
   * @return {?Date} A valid decoded timestamp, or null.
   */
  export function decodeTimestamp(str) {
    str = str.trim();
    if (str.length === 0 || str.length > MAX_SANE_LENGTH) {
      return null;
    }

    if (INTEGER_PATTERN.test(str)) {
      return decodeIntegerTimestamp(parseInt(str, 10));
    } else if (ISO_8601_PATTERN.test(str)) {
      return decodeIso8601(str);
    }
    return null;
  }

  /**
   * Decode a timestamp that is in one of the supported integer formats:
   * NTFS filetime, Unix time (s), or Unix time (ms).
   * @param {number} num An integer timestamp.
   * @return {?Date} A valid decoded timestamp, or null.
   */
  function decodeIntegerTimestamp(num) {
    // We don't ask which format integer timestamps are in, because we can guess
    // confidently by choosing the decode function that gives a sane result.
    let result;
    for (const decodeFunc
             of [decodeNtfsFiletime, decodeUnixMilliseconds,
                 decodeUnixSeconds]) {
      result = decodeFunc(num);
      if (result && result >= MIN_SANE_DATE && result <= MAX_SANE_DATE) {
        return result;
      }
    }
    // For dates that fall outside the sane range, we cannot guess which format
    // was used, but at least we can tell if the result should be in the far
    // past or the far future, and return a result that is roughly equivalent.
    return result && result < MIN_SANE_DATE ?
        new Date(MIN_SANE_DATE)  // Copy-before-return protects these two
        :
        new Date(MAX_SANE_DATE);  // constants (since Date is mutable).
  }

  /**
   * Decode a NTFS filetime timestamp with an epoch of year 1601.
   * @param {number} hundredsOfNs Each tick measures 100 nanoseconds.
   * @return {?Date}
   */
  function decodeNtfsFiletime(hundredsOfNs) {
    return createValidDate(NTFS_EPOCH.valueOf() + (hundredsOfNs / 10000));
  }

  /**
   * Decode a Unix timestamp which is counting milliseconds since 1970.
   * @param {number} milliseconds
   * @return {?Date}
   */
  function decodeUnixMilliseconds(milliseconds) {
    return createValidDate(milliseconds);
  }

  /**
   * Decode a Unix timestamp which is counting seconds since 1970.
   * @param {number} seconds
   * @return {?Date}
   */
  function decodeUnixSeconds(seconds) {
    return createValidDate(seconds * 1000);
  }

  /**
   * Decodes a timestamp string that is in ISO 8601 format.
   * @param {string} str
   * @return {?Date}
   */
  function decodeIso8601(str) {
    // If no timezone is specified, appending 'Z' means we will parse as UTC.
    // (If a timezone is already specified, appending 'Z' is simply invalid.)
    // Using UTC as a default is predictable, using local time is unpredictable.
    return createValidDate(str + 'Z') || createValidDate(str);
  }

  /**
   * Constructs a date and returns it if it is valid, otherwise returns null.
   * @param {*} arg Argument for constructing the date.
   * @return {?Date} A valid date object, or null.
   */
  function createValidDate(arg) {
    const date = new Date(arg);
    return isNaN(date) ? null : date;
  }