Source: options/permissions.js

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
/*
 *  Copyright (c) 2015-2017, Michael A. Updike All rights reserved.
 *  Licensed under the BSD-3-Clause
 *  https://opensource.org/licenses/BSD-3-Clause
 *  https://github.com/opus1269/photo-screen-saver/blob/master/LICENSE.md
 */
window.app = window.app || {};

/**
 * Handle optional permissions
 *  @namespace
 */
app.Permissions = (function() {
  'use strict';

  new ExceptionHandler();

  const chromep = new ChromePromise();

  /**
   * A permission state enum
   * @typedef {{}} app.Permissions.State
   * @property {string} notSet - never been allowed or denied
   * @property {string} allowed - user allowed
   * @property {string} denied - user denied
   * @memberOf app.Permissions
   */

  /**
   * A permission type
   * @typedef {{}} app.Permissions.Type
   * @property {string} name - name in localStorage
   * @property {string[]} permissions - array of permissions
   * @property {string[]} origins - array of origins
   * @memberOf app.Permissions
   */

  /**
   * Possible states of an {@link app.Permissions.Type}
   * @type {app.Permissions.State}
   * @const
   * @private
   * @memberOf app.Permissions
   */
  const _STATE = {
    notSet: 'notSet',
    allowed: 'allowed',
    denied: 'denied',
  };

  /**
   * Permission for access to users' Google Photos
   * @const
   * @type {app.Permissions.Type}
   * @memberOf app.Permissions
   */
  const PICASA = {
    name: 'permPicasa',
    permissions: [],
    origins: ['https://picasaweb.google.com/'],
  };

  /**
   * Permission for running in background
   * @const
   * @type {app.Permissions.Type}
   * @memberOf app.Permissions
   */
  const BACKGROUND = {
    name: 'permBackground',
    permissions: ['background'],
    origins: [],
  };

  /**
   * Persist the state of an {@link app.Permissions.Type}
   * @param {app.Permissions.Type} type - permission type
   * @param {string} value - permission state
   * @private
   * @memberOf app.Permissions
   */
  function _setState(type, value) {
    // send message to store value so items that are bound
    // to it will get storage event
    const msg = Chrome.JSONUtils.shallowCopy(Chrome.Msg.STORE);
    msg.key = type.name;
    msg.value = value;
    Chrome.Msg.send(msg).catch(() => {});
  }

  /**
   * Determine if we have the optional permissions
   * @param {app.Permissions.Type} type - permission type
   * @returns {Promise<boolean>} true if we have permissions
   * @memberOf app.Permissions
   */
  function _contains(type) {
    return chromep.permissions.contains({
      permissions: type.permissions,
      origins: type.origins,
    });
  }

  return {
    /**
     * @type {app.Permissions.Type}
     * @memberOf app.Permissions
     */
    PICASA: PICASA,

    /**
     * @type {app.Permissions.Type}
     * @memberOf app.Permissions
     */
    BACKGROUND: BACKGROUND,

    /**
     * Has user made choice on permissions
     * @param {app.Permissions.Type} type - permission type
     * @returns {boolean} true if allowed or denied
     * @memberOf app.Permissions
     */
    notSet: function(type) {
      return Chrome.Storage.get(type.name) === _STATE.notSet;
    },

    /**
     * Has the user allowed the optional permissions
     * @param {app.Permissions.Type} type - permission type
     * @returns {boolean} true if allowed
     * @memberOf app.Permissions
     */
    isAllowed: function(type) {
      return Chrome.Storage.get(type.name) === _STATE.allowed;
    },

    /**
     * Request optional permission - may block
     * @param {app.Permissions.Type} type - permission type
     * @returns {Promise<boolean>} true if permission granted
     * @memberOf app.Permissions
     */
    request: function(type) {
      let isGranted;
      return chromep.permissions.request({
        permissions: type.permissions,
        origins: type.origins,
      }).then((granted) => {
        isGranted = granted;
        if (granted) {
          _setState(type, _STATE.allowed);
          return Promise.resolve();
        } else {
          _setState(type, _STATE.denied);
          // try to remove if it has been previously granted
          return app.Permissions.remove(type);
        }
      }).then(() => {
        return Promise.resolve(isGranted);
      });
    },

    /**
     * Remove the optional permissions
     * @param {app.Permissions.Type} type - permission type
     * @returns {Promise<boolean>} true if removed
     * @memberOf app.Permissions
     */
    remove: function(type) {
      return _contains(type).then((contains) => {
        if (contains) {
          // try to remove permission
          return chromep.permissions.remove({
            permissions: type.permissions,
            origins: type.origins,
          });
        } else {
          return Promise.resolve(false);
        }
      }).then((removed) => {
        if (removed) {
          _setState(type, _STATE.notSet);
        }
        return Promise.resolve(removed);
      });
    },
  };
})();