summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/identity_internals/identity_internals.js
blob: 23cb35553cf235f4c8bceba9f6550099ed343812 (plain)
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

cr.define('identity_internals', function() {
  'use strict';

  /**
   * Creates an identity token item.
   * @param {!Object} tokenInfo Object containing token information.
   * @constructor
   */
  function TokenListItem(tokenInfo) {
    const el = cr.doc.createElement('div');
    el.data_ = tokenInfo;
    el.__proto__ = TokenListItem.prototype;
    el.decorate();
    return el;
  }

  TokenListItem.prototype = {
    __proto__: HTMLDivElement.prototype,

    /** @override */
    decorate: function() {
      this.textContent = '';
      this.id = this.data_.accessToken;

      const table = this.ownerDocument.createElement('table');
      const tbody = this.ownerDocument.createElement('tbody');
      tbody.appendChild(this.createEntry_(
          'Access Token', this.data_.accessToken, 'access-token'));
      tbody.appendChild(this.createEntry_(
          'Extension Name', this.data_.extensionName, 'extension-name'));
      tbody.appendChild(this.createEntry_(
          'Extension Id', this.data_.extensionId, 'extension-id'));
      tbody.appendChild(
          this.createEntry_('Token Status', this.data_.status, 'token-status'));
      tbody.appendChild(this.createEntry_(
          'Expiration Time', this.data_.expirationTime, 'expiration-time'));
      tbody.appendChild(this.createEntryForScopes_());
      table.appendChild(tbody);
      const tfoot = this.ownerDocument.createElement('tfoot');
      tfoot.appendChild(this.createButtons_());
      table.appendChild(tfoot);
      this.appendChild(table);
    },

    /**
     * Creates an entry for a single property of the token.
     * @param {string} label A label of the token's property name.
     * @param {string} value A value of the token property.
     * @param {string} accessor Additional class to tag the field for testing.
     * @return {HTMLElement} An HTML element with the property name and value.
     */
    createEntry_: function(label, value, accessor) {
      const row = this.ownerDocument.createElement('tr');
      const labelField = this.ownerDocument.createElement('td');
      labelField.classList.add('label');
      labelField.textContent = label;
      row.appendChild(labelField);
      const valueField = this.ownerDocument.createElement('td');
      valueField.classList.add('value');
      valueField.classList.add(accessor);
      valueField.textContent = value;
      row.appendChild(valueField);
      return row;
    },

    /**
     * Creates an entry for a list of token scopes.
     * @return {!HTMLElement} An HTML element with scopes.
     */
    createEntryForScopes_: function() {
      const row = this.ownerDocument.createElement('tr');
      const labelField = this.ownerDocument.createElement('td');
      labelField.classList.add('label');
      labelField.textContent = 'Scopes';
      row.appendChild(labelField);
      const valueField = this.ownerDocument.createElement('td');
      valueField.classList.add('value');
      valueField.classList.add('scope-list');
      this.data_.scopes.forEach(function(scope) {
        valueField.appendChild(this.ownerDocument.createTextNode(scope));
        valueField.appendChild(this.ownerDocument.createElement('br'));
      }, this);
      row.appendChild(valueField);
      return row;
    },

    /**
     * Creates buttons for the token.
     * @return {HTMLElement} An HTML element with actionable buttons for the
     *     token.
     */
    createButtons_: function() {
      const row = this.ownerDocument.createElement('tr');
      const buttonHolder = this.ownerDocument.createElement('td');
      buttonHolder.colSpan = 2;
      buttonHolder.classList.add('token-actions');
      buttonHolder.appendChild(this.createRevokeButton_());
      row.appendChild(buttonHolder);
      return row;
    },

    /**
     * Creates a revoke button with an event sending a revoke token message
     * to the controller.
     * @return {!HTMLButtonElement} The created revoke button.
     * @private
     */
    createRevokeButton_: function() {
      const revokeButton = this.ownerDocument.createElement('button');
      revokeButton.classList.add('revoke-button');
      revokeButton.addEventListener('click', function() {
        chrome.send(
            'identityInternalsRevokeToken',
            [this.data_.extensionId, this.data_.accessToken]);
      }.bind(this));
      revokeButton.textContent = 'Revoke';
      return revokeButton;
    },
  };

  /**
   * Creates a new list of identity tokens.
   * @param {Object=} opt_propertyBag Optional properties.
   * @constructor
   * @extends {cr.ui.div}
   */
  const TokenList = cr.ui.define('div');

  TokenList.prototype = {
    __proto__: HTMLDivElement.prototype,

    /** @override */
    decorate: function() {
      this.textContent = '';
      this.showTokenNodes_();
    },

    /**
     * Populates the list of tokens.
     */
    showTokenNodes_: function() {
      this.data_.forEach(function(tokenInfo) {
        this.appendChild(new TokenListItem(tokenInfo));
      }, this);
    },

    /**
     * Removes a token node related to the specifed token ID from both the
     * internals data source as well as the user internface.
     * @param {string} accessToken The id of the token to remove.
     * @private
     */
    removeTokenNode_: function(accessToken) {
      let tokenIndex;
      for (let index = 0; index < this.data_.length; index++) {
        if (this.data_[index].accessToken == accessToken) {
          tokenIndex = index;
          break;
        }
      }

      // Remove from the data_ source if token found.
      if (tokenIndex) {
        this.data_.splice(tokenIndex, 1);
      }

      // Remove from the user interface.
      const tokenNode = $(accessToken);
      if (tokenNode) {
        this.removeChild(tokenNode);
      }
    },
  };

  let tokenList;

  /**
   * Initializes the UI by asking the contoller for list of identity tokens.
   */
  function initialize() {
    chrome.send('identityInternalsGetTokens');
    tokenList = $('token-list');
    tokenList.data_ = [];
    tokenList.__proto__ = TokenList.prototype;
    tokenList.decorate();
  }

  /**
   * Callback function accepting a list of tokens to be displayed.
   * @param {!Token[]} tokens A list of tokens to be displayed
   */
  function returnTokens(tokens) {
    tokenList.data_ = tokens;
    tokenList.showTokenNodes_();
  }

  /**
   * Callback function that removes a token from UI once it has been revoked.
   * @param {!Array<string>} accessTokens Array with a single element, which is
   * an access token to be removed.
   */
  function tokenRevokeDone(accessTokens) {
    assert(accessTokens.length > 0);
    tokenList.removeTokenNode_(accessTokens[0]);
  }

  // Return an object with all of the exports.
  return {
    initialize: initialize,
    returnTokens: returnTokens,
    tokenRevokeDone: tokenRevokeDone,
  };
});

document.addEventListener('DOMContentLoaded', identity_internals.initialize);