Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/base/browser/iframe.ts
3292 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
/**
7
* Represents a window in a possible chain of iframes
8
*/
9
interface IWindowChainElement {
10
/**
11
* The window object for it
12
*/
13
readonly window: WeakRef<Window>;
14
/**
15
* The iframe element inside the window.parent corresponding to window
16
*/
17
readonly iframeElement: Element | null;
18
}
19
20
const sameOriginWindowChainCache = new WeakMap<Window, IWindowChainElement[] | null>();
21
22
function getParentWindowIfSameOrigin(w: Window): Window | null {
23
if (!w.parent || w.parent === w) {
24
return null;
25
}
26
27
// Cannot really tell if we have access to the parent window unless we try to access something in it
28
try {
29
const location = w.location;
30
const parentLocation = w.parent.location;
31
if (location.origin !== 'null' && parentLocation.origin !== 'null' && location.origin !== parentLocation.origin) {
32
return null;
33
}
34
} catch (e) {
35
return null;
36
}
37
38
return w.parent;
39
}
40
41
export class IframeUtils {
42
43
/**
44
* Returns a chain of embedded windows with the same origin (which can be accessed programmatically).
45
* Having a chain of length 1 might mean that the current execution environment is running outside of an iframe or inside an iframe embedded in a window with a different origin.
46
*/
47
private static getSameOriginWindowChain(targetWindow: Window): IWindowChainElement[] {
48
let windowChainCache = sameOriginWindowChainCache.get(targetWindow);
49
if (!windowChainCache) {
50
windowChainCache = [];
51
sameOriginWindowChainCache.set(targetWindow, windowChainCache);
52
let w: Window | null = targetWindow;
53
let parent: Window | null;
54
do {
55
parent = getParentWindowIfSameOrigin(w);
56
if (parent) {
57
windowChainCache.push({
58
window: new WeakRef(w),
59
iframeElement: w.frameElement || null
60
});
61
} else {
62
windowChainCache.push({
63
window: new WeakRef(w),
64
iframeElement: null
65
});
66
}
67
w = parent;
68
} while (w);
69
}
70
return windowChainCache.slice(0);
71
}
72
73
/**
74
* Returns the position of `childWindow` relative to `ancestorWindow`
75
*/
76
public static getPositionOfChildWindowRelativeToAncestorWindow(childWindow: Window, ancestorWindow: Window | null) {
77
78
if (!ancestorWindow || childWindow === ancestorWindow) {
79
return {
80
top: 0,
81
left: 0
82
};
83
}
84
85
let top = 0, left = 0;
86
87
const windowChain = this.getSameOriginWindowChain(childWindow);
88
89
for (const windowChainEl of windowChain) {
90
const windowInChain = windowChainEl.window.deref();
91
top += windowInChain?.scrollY ?? 0;
92
left += windowInChain?.scrollX ?? 0;
93
94
if (windowInChain === ancestorWindow) {
95
break;
96
}
97
98
if (!windowChainEl.iframeElement) {
99
break;
100
}
101
102
const boundingRect = windowChainEl.iframeElement.getBoundingClientRect();
103
top += boundingRect.top;
104
left += boundingRect.left;
105
}
106
107
return {
108
top: top,
109
left: left
110
};
111
}
112
}
113
114
/**
115
* Returns a sha-256 composed of `parentOrigin` and `salt` converted to base 32
116
*/
117
export async function parentOriginHash(parentOrigin: string, salt: string): Promise<string> {
118
// This same code is also inlined at `src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html`
119
if (!crypto.subtle) {
120
throw new Error(`'crypto.subtle' is not available so webviews will not work. This is likely because the editor is not running in a secure context (https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts).`);
121
}
122
123
const strData = JSON.stringify({ parentOrigin, salt });
124
const encoder = new TextEncoder();
125
const arrData = encoder.encode(strData);
126
const hash = await crypto.subtle.digest('sha-256', arrData);
127
return sha256AsBase32(hash);
128
}
129
130
function sha256AsBase32(bytes: ArrayBuffer): string {
131
const array = Array.from(new Uint8Array(bytes));
132
const hexArray = array.map(b => b.toString(16).padStart(2, '0')).join('');
133
// sha256 has 256 bits, so we need at most ceil(lg(2^256-1)/lg(32)) = 52 chars to represent it in base 32
134
return BigInt(`0x${hexArray}`).toString(32).padStart(52, '0');
135
}
136
137