These tags are preserved by the Closure compiler and vulcanize in order to serve the license notices embedded in the outputs. In a standalone Gerrit server, these license are also covered in the LICENSES.txt served with the documentation. When serving PG assets from a CDN, it's less obvious what the corresponding LICENSES.txt file is, since the CDN is not directly linked to a running Gerrit server. Safer to embed the licenses in the assets themselves. Change-Id: Id1add1451fad1baa7916882a6bda02c326ccc988
		
			
				
	
	
		
			187 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			187 lines
		
	
	
		
			5.2 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
/**
 | 
						|
 * @license
 | 
						|
 * Copyright (C) 2017 The Android Open Source Project
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
(function(window) {
 | 
						|
  'use strict';
 | 
						|
 | 
						|
  // Prevent redefinition.
 | 
						|
  if (window.Gerrit.Auth) { return; }
 | 
						|
 | 
						|
  const MAX_GET_TOKEN_RETRIES = 2;
 | 
						|
 | 
						|
  Gerrit.Auth = {
 | 
						|
    TYPE: {
 | 
						|
      XSRF_TOKEN: 'xsrf_token',
 | 
						|
      ACCESS_TOKEN: 'access_token',
 | 
						|
    },
 | 
						|
 | 
						|
    _type: null,
 | 
						|
    _cachedTokenPromise: null,
 | 
						|
    _defaultOptions: {},
 | 
						|
    _retriesLeft: MAX_GET_TOKEN_RETRIES,
 | 
						|
 | 
						|
    _getToken() {
 | 
						|
      return Promise.resolve(this._cachedTokenPromise);
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Enable cross-domain authentication using OAuth access token.
 | 
						|
     *
 | 
						|
     * @param {
 | 
						|
     *   function(): !Promise<{
 | 
						|
     *     access_token: string,
 | 
						|
     *     expires_at: number
 | 
						|
     *   }>
 | 
						|
     * } getToken
 | 
						|
     * @param {?{credentials:string}} defaultOptions
 | 
						|
     */
 | 
						|
    setup(getToken, defaultOptions) {
 | 
						|
      this._retriesLeft = MAX_GET_TOKEN_RETRIES;
 | 
						|
      if (getToken) {
 | 
						|
        this._type = Gerrit.Auth.TYPE.ACCESS_TOKEN;
 | 
						|
        this._cachedTokenPromise = null;
 | 
						|
        this._getToken = getToken;
 | 
						|
      }
 | 
						|
      this._defaultOptions = {};
 | 
						|
      if (defaultOptions) {
 | 
						|
        for (const p of ['credentials']) {
 | 
						|
          this._defaultOptions[p] = defaultOptions[p];
 | 
						|
        }
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * Perform network fetch with authentication.
 | 
						|
     *
 | 
						|
     * @param {string} url
 | 
						|
     * @param {Object=} opt_options
 | 
						|
     * @return {!Promise<!Response>}
 | 
						|
     */
 | 
						|
    fetch(url, opt_options) {
 | 
						|
      const options = Object.assign({
 | 
						|
        headers: new Headers(),
 | 
						|
      }, this._defaultOptions, opt_options);
 | 
						|
      if (this._type === Gerrit.Auth.TYPE.ACCESS_TOKEN) {
 | 
						|
        return this._getAccessToken().then(
 | 
						|
            accessToken => this._fetchWithAccessToken(url, options, accessToken)
 | 
						|
        );
 | 
						|
      } else {
 | 
						|
        return this._fetchWithXsrfToken(url, options);
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    _getCookie(name) {
 | 
						|
      const key = name + '=';
 | 
						|
      let result = '';
 | 
						|
      document.cookie.split(';').some(c => {
 | 
						|
        c = c.trim();
 | 
						|
        if (c.startsWith(key)) {
 | 
						|
          result = c.substring(key.length);
 | 
						|
          return true;
 | 
						|
        }
 | 
						|
      });
 | 
						|
      return result;
 | 
						|
    },
 | 
						|
 | 
						|
    _isTokenValid(token) {
 | 
						|
      if (!token) { return false; }
 | 
						|
      if (!token.access_token || !token.expires_at) { return false; }
 | 
						|
 | 
						|
      const expiration = new Date(parseInt(token.expires_at, 10) * 1000);
 | 
						|
      if (Date.now() >= expiration.getTime()) { return false; }
 | 
						|
 | 
						|
      return true;
 | 
						|
    },
 | 
						|
 | 
						|
    _fetchWithXsrfToken(url, options) {
 | 
						|
      if (options.method && options.method !== 'GET') {
 | 
						|
        const token = this._getCookie('XSRF_TOKEN');
 | 
						|
        if (token) {
 | 
						|
          options.headers.append('X-Gerrit-Auth', token);
 | 
						|
        }
 | 
						|
      }
 | 
						|
      options.credentials = 'same-origin';
 | 
						|
      return fetch(url, options);
 | 
						|
    },
 | 
						|
 | 
						|
    /**
 | 
						|
     * @return {!Promise<string>}
 | 
						|
     */
 | 
						|
    _getAccessToken() {
 | 
						|
      if (!this._cachedTokenPromise) {
 | 
						|
        this._cachedTokenPromise = this._getToken();
 | 
						|
      }
 | 
						|
      return this._cachedTokenPromise.then(token => {
 | 
						|
        if (this._isTokenValid(token)) {
 | 
						|
          this._retriesLeft = MAX_GET_TOKEN_RETRIES;
 | 
						|
          return token.access_token;
 | 
						|
        }
 | 
						|
        if (this._retriesLeft > 0) {
 | 
						|
          this._retriesLeft--;
 | 
						|
          this._cachedTokenPromise = null;
 | 
						|
          return this._getAccessToken();
 | 
						|
        }
 | 
						|
        // Fall back to anonymous access.
 | 
						|
        return null;
 | 
						|
      });
 | 
						|
    },
 | 
						|
 | 
						|
    _fetchWithAccessToken(url, options, accessToken) {
 | 
						|
      const params = [];
 | 
						|
 | 
						|
      if (accessToken) {
 | 
						|
        params.push(`access_token=${accessToken}`);
 | 
						|
        const baseUrl = Gerrit.BaseUrlBehavior.getBaseUrl();
 | 
						|
        const pathname = baseUrl ?
 | 
						|
              url.substring(url.indexOf(baseUrl) + baseUrl.length) : url;
 | 
						|
        if (!pathname.startsWith('/a/')) {
 | 
						|
          url = url.replace(pathname, '/a' + pathname);
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      const method = options.method || 'GET';
 | 
						|
      let contentType = options.headers.get('Content-Type');
 | 
						|
 | 
						|
      // For all requests with body, ensure json content type.
 | 
						|
      if (!contentType && options.body) {
 | 
						|
        contentType = 'application/json';
 | 
						|
      }
 | 
						|
 | 
						|
      if (method !== 'GET') {
 | 
						|
        options.method = 'POST';
 | 
						|
        params.push(`$m=${method}`);
 | 
						|
        // If a request is not GET, and does not have a body, ensure text/plain
 | 
						|
        // content type.
 | 
						|
        if (!contentType) {
 | 
						|
          contentType = 'text/plain';
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (contentType) {
 | 
						|
        options.headers.set('Content-Type', 'text/plain');
 | 
						|
        params.push(`$ct=${encodeURIComponent(contentType)}`);
 | 
						|
      }
 | 
						|
 | 
						|
      if (params.length) {
 | 
						|
        url = url + (url.indexOf('?') === -1 ? '?' : '&') + params.join('&');
 | 
						|
      }
 | 
						|
      return fetch(url, options);
 | 
						|
    },
 | 
						|
  };
 | 
						|
 | 
						|
  window.Gerrit.Auth = Gerrit.Auth;
 | 
						|
})(window);
 |