File size: 6,121 Bytes
30c32c8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
/* eslint-disable no-unused-vars */

/**
 * Responsible for determining various policies related to custom extension security.
 * The default implementation prevents automatic extension loading, but grants any
 * loaded extensions the maximum possible capabilities so as to retain compatibility
 * with a vanilla scratch-vm. You may override properties of an instance of this class
 * to customize the security policies as you see fit, for example:
 * ```js
 * vm.securityManager.getSandboxMode = (url) => {
 *   if (url.startsWith("https://example.com/")) {
 *     return "unsandboxed";
 *   }
 *   return "iframe";
 * };
 * vm.securityManager.canAutomaticallyLoadExtension = (url) => {
 *   return confirm("Automatically load extension: " + url);
 * };
 * vm.securityManager.canFetch = (url) => {
 *   return url.startsWith('https://turbowarp.org/');
 * };
 * vm.securityManager.canOpenWindow = (url) => {
 *   return url.startsWith('https://turbowarp.org/');
 * };
 * vm.securityManager.canRedirect = (url) => {
 *   return url.startsWith('https://turbowarp.org/');
 * };
 * ```
 */
class SecurityManager {
    /**
     * Determine the typeof sandbox to use for a certain custom extension.
     * @param {string} extensionURL The URL of the custom extension.
     * @returns {'worker'|'iframe'|'unsandboxed'|Promise<'worker'|'iframe'|'unsandboxed'>}
     */
    getSandboxMode (extensionURL) {
        // Default to worker for Scratch compatibility
        return Promise.resolve('worker');
    }

    /**
     * Determine whether a custom extension that was stored inside a project may be
     * loaded. You could, for example, ask the user to confirm loading an extension
     * before resolving.
     * @param {string} extensionURL The URL of the custom extension.
     * @returns {Promise<boolean>|boolean}
     */
    canLoadExtensionFromProject (extensionURL) {
        // Default to false for security
        return Promise.resolve(false);
    }
    
    /**
     * Allows last-minute changing the real URL of the extension that gets loaded.
     * @param {*} extensionURL The URL requested to be loaded.
     * @returns {Promise<string>|string} The URL to actually load.
     */
    rewriteExtensionURL (extensionURL) {
        return Promise.resolve(extensionURL);
    }

    /**
     * Determine whether an extension is allowed to fetch a remote resource URL.
     * This only applies to unsandboxed extensions that use the appropriate Scratch.* APIs.
     * Sandboxed extensions ignore this entirely as there is no way to force them to use our APIs.
     * data: and blob: URLs are always allowed (this method is never called).
     * @param {string} resourceURL
     * @returns {Promise<boolean>|boolean}
     */
    canFetch (resourceURL) {
        // By default, allow any requests.
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to open a new window or tab to a given URL.
     * This only applies to unsandboxed extensions. Sandboxed extensions are unable to open windows.
     * javascript: URLs are always rejected (this method is never called).
     * @param {string} websiteURL
     * @returns {Promise<boolean>|boolean}
     */
    canOpenWindow (websiteURL) {
        // By default, allow all.
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to redirect the current tab to a given URL.
     * This only applies to unsandboxed extensions. Sandboxed extensions are unable to redirect the parent
     * window, but are free to redirect their own sandboxed window.
     * javascript: URLs are always rejected (this method is never called).
     * @param {string} websiteURL
     * @returns {Promise<boolean>|boolean}
     */
    canRedirect (websiteURL) {
        // By default, allow all.
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to record audio from the user's microphone.
     * This could include raw audio data or a transcriptions.
     * Note that, even if this returns true, success is not guaranteed.
     * @returns {Promise<boolean>|boolean}
     */
    canRecordAudio () {
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to record video from the user's camera.
     * Note that, even if this returns true, success is not guaranteed.
     * @returns {Promise<boolean>|boolean}
     */
    canRecordVideo () {
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to read values from the user's clipboard
     * without user interaction.
     * Note that, even if this returns true, success is not guaranteed.
     * @returns {Promise<boolean>|boolean}
     */
    canReadClipboard () {
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to show notifications.
     * Note that, even if this returns true, success is not guaranteed.
     * @returns {Promise<boolean>|boolean}
     */
    canNotify () {
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to find the user's precise location using GPS
     * and other techniques. Note that, even if this returns true, success is not guaranteed.
     * @returns {Promise<boolean>|boolean}
     */
    canGeolocate () {
        return Promise.resolve(true);
    }

    /**
     * Determine whether an extension is allowed to embed content from a given URL.
     * @param {string} documentURL The URL of the embed.
     * @returns {Promise<boolean>|boolean}
     */
    canEmbed (documentURL) {
        return Promise.resolve(true);
    }

    /**
     * pm: Used to prompt the user if they would like to unsandbox a feature in the extension.
     * @returns {Promise<boolean>|boolean}
     */
    canUnsandbox() {
        return Promise.resolve(false);
    }

    shouldUseLocal(refrenceName) {
        return Promise.resolve(!confirm(`it seems that the extension ${refrenceName} has been updated, use the up-to-date code?`))
    }
}

module.exports = SecurityManager;