xframelib 0.5.7 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +117 -68
- package/dist/api/Token.d.ts +1 -6
- package/dist/api/User.d.ts +9 -5
- package/dist/controls/layoutcontainer/LayoutManager.d.ts +10 -5
- package/dist/controls/layoutcontainer/index.d.ts +1 -1
- package/dist/controls/layoutcontainer/layout.vue.d.ts +19 -8
- package/dist/controls/vuewindow/window/index.vue.d.ts +1 -0
- package/dist/core/IModel.d.ts +0 -5
- package/dist/index.cjs +13 -8
- package/dist/index.css +100 -100
- package/dist/index.js +12 -7
- package/dist/model/Config.d.ts +19 -11
- package/dist/model/Constants.d.ts +2 -2
- package/dist/model/IRole.d.ts +4 -0
- package/dist/model/{Token.d.ts → IUserModel.d.ts} +18 -21
- package/dist/model/Layout.d.ts +11 -3
- package/dist/model/index.d.ts +2 -1
- package/dist/permission/RoleSysRightHelper.d.ts +27 -0
- package/dist/permission/filter.d.ts +15 -8
- package/dist/permission/index.d.ts +1 -0
- package/dist/permission/right.d.ts +1 -1
- package/dist/public/mitm.html +180 -180
- package/dist/public/sw.js +128 -128
- package/dist/utils/TokenHelper.d.ts +1 -1
- package/dist/utils/XXTEA.d.ts +15 -0
- package/dist/utils/index.d.ts +1 -0
- package/package.json +13 -13
package/dist/model/Config.d.ts
CHANGED
|
@@ -42,9 +42,13 @@ export interface IUIObject {
|
|
|
42
42
|
*/
|
|
43
43
|
export interface IServiceURL {
|
|
44
44
|
/**
|
|
45
|
-
*
|
|
45
|
+
* 用户登录验证服务(统一用户登录:后台)
|
|
46
46
|
*/
|
|
47
47
|
LoginAuthURL?: string;
|
|
48
|
+
/**
|
|
49
|
+
* 用户登录界面(统一用户登录界面:前台)
|
|
50
|
+
*/
|
|
51
|
+
UILoginURL?: string;
|
|
48
52
|
/**
|
|
49
53
|
* 文件管理服务地址(统一文件管理:后台)
|
|
50
54
|
*/
|
|
@@ -52,11 +56,15 @@ export interface IServiceURL {
|
|
|
52
56
|
/**
|
|
53
57
|
* 文件管理(统一文件管理:前台)
|
|
54
58
|
*/
|
|
55
|
-
|
|
59
|
+
UIFileURL?: string;
|
|
56
60
|
/**
|
|
57
|
-
*
|
|
61
|
+
* 在线日志服务(统一日志记录)
|
|
58
62
|
*/
|
|
59
63
|
LogServiceURL?: string;
|
|
64
|
+
/**
|
|
65
|
+
* 图标在线服务地址
|
|
66
|
+
*/
|
|
67
|
+
IconServiceURL?: string;
|
|
60
68
|
/**
|
|
61
69
|
* Axios普通WebAPI的BaseURL
|
|
62
70
|
* 全局默认的http请求地址(一般与主hprose相同或不同);文件上传地址
|
|
@@ -76,21 +84,21 @@ export interface IServiceURL {
|
|
|
76
84
|
*/
|
|
77
85
|
export interface IMapKeys {
|
|
78
86
|
/**
|
|
79
|
-
* 天地图Key
|
|
87
|
+
* 天地图Key ,单个或数组
|
|
80
88
|
*/
|
|
81
|
-
TDTKey?: string;
|
|
89
|
+
TDTKey?: string | string[];
|
|
82
90
|
/**
|
|
83
|
-
* MapboxKey
|
|
91
|
+
* MapboxKey ,单个或数组
|
|
84
92
|
*/
|
|
85
|
-
MapboxKey?: string;
|
|
93
|
+
MapboxKey?: string | string[];
|
|
86
94
|
/**
|
|
87
|
-
* Cesium Key
|
|
95
|
+
* Cesium Key ,单个或数组
|
|
88
96
|
*/
|
|
89
|
-
CesiumKey?: string;
|
|
97
|
+
CesiumKey?: string | string[];
|
|
90
98
|
/**
|
|
91
|
-
* Google地图Key
|
|
99
|
+
* Google地图Key ,单个或数组
|
|
92
100
|
*/
|
|
93
|
-
GoogleKey?: string;
|
|
101
|
+
GoogleKey?: string | string[];
|
|
94
102
|
/**
|
|
95
103
|
* 其他扩展的Key属性
|
|
96
104
|
*/
|
|
@@ -7,9 +7,9 @@ export declare const TOKEN_REFRESH_TIME: number;
|
|
|
7
7
|
*/
|
|
8
8
|
export declare const USER_TOKEN_API: {
|
|
9
9
|
Login: string;
|
|
10
|
-
|
|
10
|
+
ChangeMyPwd: string;
|
|
11
11
|
Logout: string;
|
|
12
|
-
ChangePWD: string;
|
|
13
12
|
RefreshToken: string;
|
|
14
13
|
CheckToken: string;
|
|
14
|
+
GetSystemRights: string;
|
|
15
15
|
};
|
package/dist/model/IRole.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface IRoleRoute {
|
|
|
8
8
|
title?: string;
|
|
9
9
|
index?: number;
|
|
10
10
|
children?: IRoleRoute[];
|
|
11
|
+
selected?: boolean;
|
|
11
12
|
}
|
|
12
13
|
/**
|
|
13
14
|
* Widget菜单控制
|
|
@@ -18,6 +19,7 @@ export interface IRoleWidgetMenu {
|
|
|
18
19
|
path?: string;
|
|
19
20
|
type?: number;
|
|
20
21
|
children?: Array<IRoleWidgetMenu>;
|
|
22
|
+
selected?: boolean;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Widget组件权限控制
|
|
@@ -51,6 +53,7 @@ export interface IRoleWidget {
|
|
|
51
53
|
* 所属组,用于业务分类
|
|
52
54
|
*/
|
|
53
55
|
group?: string;
|
|
56
|
+
selected?: boolean;
|
|
54
57
|
}
|
|
55
58
|
/**
|
|
56
59
|
* 功能点列表,用于功能点上报和权限过滤
|
|
@@ -59,6 +62,7 @@ export interface IRoleFunction {
|
|
|
59
62
|
id: string;
|
|
60
63
|
name: string;
|
|
61
64
|
children?: Array<IRoleFunction>;
|
|
65
|
+
selected?: boolean;
|
|
62
66
|
}
|
|
63
67
|
/**
|
|
64
68
|
* 系统权限路由菜单-总对象
|
|
@@ -2,15 +2,10 @@
|
|
|
2
2
|
* 当前存储的token对象
|
|
3
3
|
*/
|
|
4
4
|
export interface ITokenInfo {
|
|
5
|
-
id: string;
|
|
6
|
-
name: string;
|
|
7
5
|
token: string;
|
|
8
6
|
expire: string;
|
|
9
7
|
refresh: string;
|
|
10
|
-
issystem?: boolean;
|
|
11
|
-
issecurity?: boolean;
|
|
12
8
|
appkey?: string;
|
|
13
|
-
role?: string;
|
|
14
9
|
}
|
|
15
10
|
/**
|
|
16
11
|
* 单个token对象内容
|
|
@@ -46,25 +41,27 @@ export interface ISystemUser {
|
|
|
46
41
|
/**
|
|
47
42
|
* 用户ID
|
|
48
43
|
*/
|
|
49
|
-
id
|
|
44
|
+
id?: string;
|
|
50
45
|
/**
|
|
51
46
|
* 用户名
|
|
52
47
|
*/
|
|
53
|
-
name
|
|
48
|
+
name?: string;
|
|
49
|
+
doubletoken?: IDoubleToken;
|
|
50
|
+
roles?: IUserRole[];
|
|
54
51
|
/**
|
|
55
|
-
*
|
|
52
|
+
* 外部绑定用户信息ID
|
|
56
53
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
54
|
+
bindid?: string;
|
|
55
|
+
}
|
|
56
|
+
export interface IUserRole {
|
|
57
|
+
id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
level: number;
|
|
60
|
+
createrid?: string;
|
|
61
|
+
syslist?: IUserSystem[];
|
|
62
|
+
}
|
|
63
|
+
export interface IUserSystem {
|
|
64
|
+
id: string;
|
|
65
|
+
name: string;
|
|
66
|
+
version: string;
|
|
70
67
|
}
|
package/dist/model/Layout.d.ts
CHANGED
|
@@ -24,6 +24,10 @@ export interface IWidgetLayout {
|
|
|
24
24
|
height?: string;
|
|
25
25
|
}
|
|
26
26
|
export interface IWidgetConfig {
|
|
27
|
+
/**
|
|
28
|
+
* Layout标识名,以支撑多个布局使用
|
|
29
|
+
*/
|
|
30
|
+
layoutID?: string;
|
|
27
31
|
/**
|
|
28
32
|
* 唯一ID,与组件名一致
|
|
29
33
|
*/
|
|
@@ -57,13 +61,13 @@ export interface IWidgetConfig {
|
|
|
57
61
|
*/
|
|
58
62
|
preload?: boolean;
|
|
59
63
|
/**
|
|
60
|
-
*
|
|
64
|
+
* 前置组件 ID,一般也就是bindid
|
|
61
65
|
*/
|
|
62
66
|
afterid?: string;
|
|
63
67
|
/**
|
|
64
|
-
*
|
|
68
|
+
* 20220424 WM:暂时去掉,容易混乱和循环引用
|
|
69
|
+
* 绑定依赖组件ID,不一定有afterid
|
|
65
70
|
*/
|
|
66
|
-
bindid?: string;
|
|
67
71
|
/**
|
|
68
72
|
* 所属组,用于业务分类
|
|
69
73
|
*/
|
|
@@ -72,4 +76,8 @@ export interface IWidgetConfig {
|
|
|
72
76
|
* 外部定义布局(备用)
|
|
73
77
|
*/
|
|
74
78
|
layout?: IWidgetLayout;
|
|
79
|
+
/**
|
|
80
|
+
* 扩展属性,支持应用
|
|
81
|
+
*/
|
|
82
|
+
[props: string]: any;
|
|
75
83
|
}
|
package/dist/model/index.d.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { ISysRoleRight } from '../model/IRole';
|
|
2
|
+
/**
|
|
3
|
+
* 删除非选中节点
|
|
4
|
+
* @param childrenNodes
|
|
5
|
+
*/
|
|
6
|
+
export declare function handleNodes(childrenNodes: any[]): void;
|
|
7
|
+
/**
|
|
8
|
+
* 新旧合并
|
|
9
|
+
* @param newNodes
|
|
10
|
+
* @param oldNodes
|
|
11
|
+
* @param fieldName
|
|
12
|
+
*/
|
|
13
|
+
export declare function mergeNodes(newNodes: any[], oldNodes: any[], fieldName?: string): void;
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param jsonObj
|
|
17
|
+
* @param jsonObjOld
|
|
18
|
+
* @param groupName 'routes'|'widgetMenu'|'widgets'|'functions'
|
|
19
|
+
* @param fieldName 主键字段名
|
|
20
|
+
*/
|
|
21
|
+
export declare function mergeNodesAll(jsonObj: ISysRoleRight, jsonObjOld: ISysRoleRight, groupName: string, fieldName?: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* 融合过滤角色权限功能
|
|
24
|
+
* @param jsonObjArray ISysRoleRight对象数组
|
|
25
|
+
* @returns
|
|
26
|
+
*/
|
|
27
|
+
export declare function mergeFilterRoleSysRight(jsonObjArray: any[]): ISysRoleRight | undefined;
|
|
@@ -8,31 +8,38 @@ declare type IWidgetMenu = any;
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function getCurrentSystemRight(): ISysRoleRight | undefined;
|
|
10
10
|
/**
|
|
11
|
-
*
|
|
11
|
+
* 获取用户角色权限列表对象
|
|
12
12
|
* @param sysID 系统ID
|
|
13
|
-
* @param
|
|
14
|
-
* @param fullSysRights 默认全部,调试开发使用
|
|
13
|
+
* @param isSuperLevel 当前用户的最高等级
|
|
15
14
|
* @returns
|
|
16
15
|
*/
|
|
17
|
-
export declare function getSystemRoleRight(sysID: string,
|
|
16
|
+
export declare function getSystemRoleRight(sysID: string, isSuperLevel?: boolean): Promise<ISysRoleRight | undefined>;
|
|
18
17
|
/**
|
|
19
18
|
* 获取授权的Route 集合
|
|
19
|
+
* @param bussinessRoutes 全部业务路由
|
|
20
|
+
* @param roleLevel 角色级别,默认为普通用户,如果为0,则是超级管理员
|
|
20
21
|
* @returns
|
|
21
22
|
*/
|
|
22
|
-
export declare function getRoutes(bussinessRoutes: Array<RouteRecordRaw
|
|
23
|
+
export declare function getRoutes(bussinessRoutes: Array<RouteRecordRaw>, roleLevel?: number): Array<RouteRecordRaw> | undefined;
|
|
23
24
|
/**
|
|
24
25
|
* 获取授权的Widget Menu集合
|
|
26
|
+
* @param widgetMenuConfig 全部widget配置
|
|
27
|
+
* @param roleLevel 角色级别,默认为普通用户,如果为0,则是超级管理员
|
|
25
28
|
* @returns
|
|
26
29
|
*/
|
|
27
|
-
export declare function getWidgetMenus(widgetMenuConfig: Array<IWidgetMenu
|
|
30
|
+
export declare function getWidgetMenus(widgetMenuConfig: Array<IWidgetMenu>, roleLevel?: number): Array<IWidgetMenu> | undefined;
|
|
28
31
|
/**
|
|
29
32
|
* 获取授权的 widget配置对象集合
|
|
33
|
+
* @param widgetConfig 全部
|
|
34
|
+
* @param roleLevel 角色级别,默认为普通用户,如果为0,则是超级管理员
|
|
30
35
|
* @returns
|
|
31
36
|
*/
|
|
32
|
-
export declare function getWidgetConfig(widgetConfig?: Array<IWidgetConfig
|
|
37
|
+
export declare function getWidgetConfig(widgetConfig?: Array<IWidgetConfig>, roleLevel?: number): Array<IWidgetConfig> | undefined;
|
|
33
38
|
/**
|
|
34
39
|
* 获取授权的功能点集合
|
|
40
|
+
* @param functionList 全部功能列表
|
|
41
|
+
* @param roleLevel 角色级别,默认为普通用户,如果为0,则是超级管理员
|
|
35
42
|
* @returns
|
|
36
43
|
*/
|
|
37
|
-
export declare function getFunctions(functionList?: Array<IRoleFunction
|
|
44
|
+
export declare function getFunctions(functionList?: Array<IRoleFunction>, roleLevel?: number): IRoleFunction[] | undefined;
|
|
38
45
|
export {};
|
|
@@ -8,7 +8,7 @@ export declare function getRight(): ISysRoleRight | undefined;
|
|
|
8
8
|
* 设置 系统角色权限 对象
|
|
9
9
|
* @param sysRoleRight 系统角色权限对象
|
|
10
10
|
*/
|
|
11
|
-
export declare function setRight(sysRoleRight
|
|
11
|
+
export declare function setRight(sysRoleRight?: ISysRoleRight): void;
|
|
12
12
|
/**
|
|
13
13
|
* 清除
|
|
14
14
|
*/
|
package/dist/public/mitm.html
CHANGED
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
<!--
|
|
2
|
-
mitm.html is the lite "man in the middle"
|
|
3
|
-
|
|
4
|
-
This is only meant to signal the opener's messageChannel to
|
|
5
|
-
the service worker - when that is done this mitm can be closed
|
|
6
|
-
but it's better to keep it alive since this also stops the sw
|
|
7
|
-
from restarting
|
|
8
|
-
|
|
9
|
-
The service worker is capable of intercepting all request and fork their
|
|
10
|
-
own "fake" response - wish we are going to craft
|
|
11
|
-
when the worker then receives a stream then the worker will tell the opener
|
|
12
|
-
to open up a link that will start the download
|
|
13
|
-
-->
|
|
14
|
-
<script>
|
|
15
|
-
// This will prevent the sw from restarting
|
|
16
|
-
let keepAlive = () => {
|
|
17
|
-
keepAlive = () => {};
|
|
18
|
-
var ping = location.href.substring(0, location.href.lastIndexOf('/')) + '/ping';
|
|
19
|
-
var interval = setInterval(() => {
|
|
20
|
-
if (sw) {
|
|
21
|
-
sw.postMessage('ping');
|
|
22
|
-
} else {
|
|
23
|
-
fetch(ping).then(res => res.text(!res.ok && clearInterval(interval)));
|
|
24
|
-
}
|
|
25
|
-
}, 10000);
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// message event is the first thing we need to setup a listner for
|
|
29
|
-
// don't want the opener to do a random timeout - instead they can listen for
|
|
30
|
-
// the ready event
|
|
31
|
-
// but since we need to wait for the Service Worker registration, we store the
|
|
32
|
-
// message for later
|
|
33
|
-
let messages = [];
|
|
34
|
-
window.onmessage = evt => messages.push(evt);
|
|
35
|
-
|
|
36
|
-
let sw = null;
|
|
37
|
-
let scope = '';
|
|
38
|
-
|
|
39
|
-
function registerWorker() {
|
|
40
|
-
return navigator.serviceWorker
|
|
41
|
-
.getRegistration('./')
|
|
42
|
-
.then(swReg => {
|
|
43
|
-
return swReg || navigator.serviceWorker.register('sw.js', { scope: './' });
|
|
44
|
-
})
|
|
45
|
-
.then(swReg => {
|
|
46
|
-
const swRegTmp = swReg.installing || swReg.waiting;
|
|
47
|
-
|
|
48
|
-
scope = swReg.scope;
|
|
49
|
-
|
|
50
|
-
return (
|
|
51
|
-
(sw = swReg.active) ||
|
|
52
|
-
new Promise(resolve => {
|
|
53
|
-
swRegTmp.addEventListener(
|
|
54
|
-
'statechange',
|
|
55
|
-
(fn = () => {
|
|
56
|
-
if (swRegTmp.state === 'activated') {
|
|
57
|
-
swRegTmp.removeEventListener('statechange', fn);
|
|
58
|
-
sw = swReg.active;
|
|
59
|
-
resolve();
|
|
60
|
-
}
|
|
61
|
-
})
|
|
62
|
-
);
|
|
63
|
-
})
|
|
64
|
-
);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
// Now that we have the Service Worker registered we can process messages
|
|
69
|
-
function onMessage(event) {
|
|
70
|
-
let { data, ports, origin } = event;
|
|
71
|
-
|
|
72
|
-
// It's important to have a messageChannel, don't want to interfere
|
|
73
|
-
// with other simultaneous downloads
|
|
74
|
-
if (!ports || !ports.length) {
|
|
75
|
-
throw new TypeError("[StreamSaver] You didn't send a messageChannel");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (typeof data !== 'object') {
|
|
79
|
-
throw new TypeError("[StreamSaver] You didn't send a object");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// the default public service worker for StreamSaver is shared among others.
|
|
83
|
-
// so all download links needs to be prefixed to avoid any other conflict
|
|
84
|
-
data.origin = origin;
|
|
85
|
-
|
|
86
|
-
// if we ever (in some feature versoin of streamsaver) would like to
|
|
87
|
-
// redirect back to the page of who initiated a http request
|
|
88
|
-
data.referrer = data.referrer || document.referrer || origin;
|
|
89
|
-
|
|
90
|
-
// pass along version for possible backwards compatibility in sw.js
|
|
91
|
-
data.streamSaverVersion = new URLSearchParams(location.search).get('version');
|
|
92
|
-
|
|
93
|
-
if (data.streamSaverVersion === '1.2.0') {
|
|
94
|
-
console.warn('[StreamSaver] please update streamsaver');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/** @since v2.0.0 */
|
|
98
|
-
if (!data.headers) {
|
|
99
|
-
console.warn(
|
|
100
|
-
"[StreamSaver] pass `data.headers` that you would like to pass along to the service worker\nit should be a 2D array or a key/val object that fetch's Headers api accepts"
|
|
101
|
-
);
|
|
102
|
-
} else {
|
|
103
|
-
// test if it's correct
|
|
104
|
-
// should thorw a typeError if not
|
|
105
|
-
new Headers(data.headers);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/** @since v2.0.0 */
|
|
109
|
-
if (typeof data.filename === 'string') {
|
|
110
|
-
console.warn(
|
|
111
|
-
"[StreamSaver] You shouldn't send `data.filename` anymore. It should be included in the Content-Disposition header option"
|
|
112
|
-
);
|
|
113
|
-
// Do what File constructor do with fileNames
|
|
114
|
-
data.filename = data.filename.replace(/\//g, ':');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
/** @since v2.0.0 */
|
|
118
|
-
if (data.size) {
|
|
119
|
-
console.warn(
|
|
120
|
-
"[StreamSaver] You shouldn't send `data.size` anymore. It should be included in the content-length header option"
|
|
121
|
-
);
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/** @since v2.0.0 */
|
|
125
|
-
if (data.readableStream) {
|
|
126
|
-
console.warn(
|
|
127
|
-
'[StreamSaver] You should send the readableStream in the messageChannel, not throught mitm'
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** @since v2.0.0 */
|
|
132
|
-
if (!data.pathname) {
|
|
133
|
-
console.warn('[StreamSaver] Please send `data.pathname` (eg: /pictures/summer.jpg)');
|
|
134
|
-
data.pathname = Math.random().toString().slice(-6) + '/' + data.filename;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
// remove all leading slashes
|
|
138
|
-
data.pathname = data.pathname.replace(/^\/+/g, '');
|
|
139
|
-
|
|
140
|
-
// remove protocol
|
|
141
|
-
let org = origin.replace(/(^\w+:|^)\/\//, '');
|
|
142
|
-
|
|
143
|
-
// set the absolute pathname to the download url.
|
|
144
|
-
data.url = new URL(`${scope + org}/${data.pathname}`).toString();
|
|
145
|
-
|
|
146
|
-
if (!data.url.startsWith(`${scope + org}/`)) {
|
|
147
|
-
throw new TypeError('[StreamSaver] bad `data.pathname`');
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// This sends the message data as well as transferring
|
|
151
|
-
// messageChannel.port2 to the service worker. The service worker can
|
|
152
|
-
// then use the transferred port to reply via postMessage(), which
|
|
153
|
-
// will in turn trigger the onmessage handler on messageChannel.port1.
|
|
154
|
-
|
|
155
|
-
const transferable = data.readableStream ? [ports[0], data.readableStream] : [ports[0]];
|
|
156
|
-
|
|
157
|
-
if (!(data.readableStream || data.transferringReadable)) {
|
|
158
|
-
keepAlive();
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
return sw.postMessage(data, transferable);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (window.opener) {
|
|
165
|
-
// The opener can't listen to onload event, so we need to help em out!
|
|
166
|
-
// (telling them that we are ready to accept postMessage's)
|
|
167
|
-
window.opener.postMessage('StreamSaver::loadedPopup', '*');
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (navigator.serviceWorker) {
|
|
171
|
-
registerWorker().then(() => {
|
|
172
|
-
window.onmessage = onMessage;
|
|
173
|
-
messages.forEach(window.onmessage);
|
|
174
|
-
});
|
|
175
|
-
} else {
|
|
176
|
-
// FF can ping sw with fetch from a secure hidden iframe
|
|
177
|
-
// shouldn't really be possible?
|
|
178
|
-
keepAlive();
|
|
179
|
-
}
|
|
180
|
-
</script>
|
|
1
|
+
<!--
|
|
2
|
+
mitm.html is the lite "man in the middle"
|
|
3
|
+
|
|
4
|
+
This is only meant to signal the opener's messageChannel to
|
|
5
|
+
the service worker - when that is done this mitm can be closed
|
|
6
|
+
but it's better to keep it alive since this also stops the sw
|
|
7
|
+
from restarting
|
|
8
|
+
|
|
9
|
+
The service worker is capable of intercepting all request and fork their
|
|
10
|
+
own "fake" response - wish we are going to craft
|
|
11
|
+
when the worker then receives a stream then the worker will tell the opener
|
|
12
|
+
to open up a link that will start the download
|
|
13
|
+
-->
|
|
14
|
+
<script>
|
|
15
|
+
// This will prevent the sw from restarting
|
|
16
|
+
let keepAlive = () => {
|
|
17
|
+
keepAlive = () => {};
|
|
18
|
+
var ping = location.href.substring(0, location.href.lastIndexOf('/')) + '/ping';
|
|
19
|
+
var interval = setInterval(() => {
|
|
20
|
+
if (sw) {
|
|
21
|
+
sw.postMessage('ping');
|
|
22
|
+
} else {
|
|
23
|
+
fetch(ping).then(res => res.text(!res.ok && clearInterval(interval)));
|
|
24
|
+
}
|
|
25
|
+
}, 10000);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// message event is the first thing we need to setup a listner for
|
|
29
|
+
// don't want the opener to do a random timeout - instead they can listen for
|
|
30
|
+
// the ready event
|
|
31
|
+
// but since we need to wait for the Service Worker registration, we store the
|
|
32
|
+
// message for later
|
|
33
|
+
let messages = [];
|
|
34
|
+
window.onmessage = evt => messages.push(evt);
|
|
35
|
+
|
|
36
|
+
let sw = null;
|
|
37
|
+
let scope = '';
|
|
38
|
+
|
|
39
|
+
function registerWorker() {
|
|
40
|
+
return navigator.serviceWorker
|
|
41
|
+
.getRegistration('./')
|
|
42
|
+
.then(swReg => {
|
|
43
|
+
return swReg || navigator.serviceWorker.register('sw.js', { scope: './' });
|
|
44
|
+
})
|
|
45
|
+
.then(swReg => {
|
|
46
|
+
const swRegTmp = swReg.installing || swReg.waiting;
|
|
47
|
+
|
|
48
|
+
scope = swReg.scope;
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
(sw = swReg.active) ||
|
|
52
|
+
new Promise(resolve => {
|
|
53
|
+
swRegTmp.addEventListener(
|
|
54
|
+
'statechange',
|
|
55
|
+
(fn = () => {
|
|
56
|
+
if (swRegTmp.state === 'activated') {
|
|
57
|
+
swRegTmp.removeEventListener('statechange', fn);
|
|
58
|
+
sw = swReg.active;
|
|
59
|
+
resolve();
|
|
60
|
+
}
|
|
61
|
+
})
|
|
62
|
+
);
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Now that we have the Service Worker registered we can process messages
|
|
69
|
+
function onMessage(event) {
|
|
70
|
+
let { data, ports, origin } = event;
|
|
71
|
+
|
|
72
|
+
// It's important to have a messageChannel, don't want to interfere
|
|
73
|
+
// with other simultaneous downloads
|
|
74
|
+
if (!ports || !ports.length) {
|
|
75
|
+
throw new TypeError("[StreamSaver] You didn't send a messageChannel");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof data !== 'object') {
|
|
79
|
+
throw new TypeError("[StreamSaver] You didn't send a object");
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// the default public service worker for StreamSaver is shared among others.
|
|
83
|
+
// so all download links needs to be prefixed to avoid any other conflict
|
|
84
|
+
data.origin = origin;
|
|
85
|
+
|
|
86
|
+
// if we ever (in some feature versoin of streamsaver) would like to
|
|
87
|
+
// redirect back to the page of who initiated a http request
|
|
88
|
+
data.referrer = data.referrer || document.referrer || origin;
|
|
89
|
+
|
|
90
|
+
// pass along version for possible backwards compatibility in sw.js
|
|
91
|
+
data.streamSaverVersion = new URLSearchParams(location.search).get('version');
|
|
92
|
+
|
|
93
|
+
if (data.streamSaverVersion === '1.2.0') {
|
|
94
|
+
console.warn('[StreamSaver] please update streamsaver');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** @since v2.0.0 */
|
|
98
|
+
if (!data.headers) {
|
|
99
|
+
console.warn(
|
|
100
|
+
"[StreamSaver] pass `data.headers` that you would like to pass along to the service worker\nit should be a 2D array or a key/val object that fetch's Headers api accepts"
|
|
101
|
+
);
|
|
102
|
+
} else {
|
|
103
|
+
// test if it's correct
|
|
104
|
+
// should thorw a typeError if not
|
|
105
|
+
new Headers(data.headers);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** @since v2.0.0 */
|
|
109
|
+
if (typeof data.filename === 'string') {
|
|
110
|
+
console.warn(
|
|
111
|
+
"[StreamSaver] You shouldn't send `data.filename` anymore. It should be included in the Content-Disposition header option"
|
|
112
|
+
);
|
|
113
|
+
// Do what File constructor do with fileNames
|
|
114
|
+
data.filename = data.filename.replace(/\//g, ':');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** @since v2.0.0 */
|
|
118
|
+
if (data.size) {
|
|
119
|
+
console.warn(
|
|
120
|
+
"[StreamSaver] You shouldn't send `data.size` anymore. It should be included in the content-length header option"
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/** @since v2.0.0 */
|
|
125
|
+
if (data.readableStream) {
|
|
126
|
+
console.warn(
|
|
127
|
+
'[StreamSaver] You should send the readableStream in the messageChannel, not throught mitm'
|
|
128
|
+
);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** @since v2.0.0 */
|
|
132
|
+
if (!data.pathname) {
|
|
133
|
+
console.warn('[StreamSaver] Please send `data.pathname` (eg: /pictures/summer.jpg)');
|
|
134
|
+
data.pathname = Math.random().toString().slice(-6) + '/' + data.filename;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// remove all leading slashes
|
|
138
|
+
data.pathname = data.pathname.replace(/^\/+/g, '');
|
|
139
|
+
|
|
140
|
+
// remove protocol
|
|
141
|
+
let org = origin.replace(/(^\w+:|^)\/\//, '');
|
|
142
|
+
|
|
143
|
+
// set the absolute pathname to the download url.
|
|
144
|
+
data.url = new URL(`${scope + org}/${data.pathname}`).toString();
|
|
145
|
+
|
|
146
|
+
if (!data.url.startsWith(`${scope + org}/`)) {
|
|
147
|
+
throw new TypeError('[StreamSaver] bad `data.pathname`');
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// This sends the message data as well as transferring
|
|
151
|
+
// messageChannel.port2 to the service worker. The service worker can
|
|
152
|
+
// then use the transferred port to reply via postMessage(), which
|
|
153
|
+
// will in turn trigger the onmessage handler on messageChannel.port1.
|
|
154
|
+
|
|
155
|
+
const transferable = data.readableStream ? [ports[0], data.readableStream] : [ports[0]];
|
|
156
|
+
|
|
157
|
+
if (!(data.readableStream || data.transferringReadable)) {
|
|
158
|
+
keepAlive();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return sw.postMessage(data, transferable);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if (window.opener) {
|
|
165
|
+
// The opener can't listen to onload event, so we need to help em out!
|
|
166
|
+
// (telling them that we are ready to accept postMessage's)
|
|
167
|
+
window.opener.postMessage('StreamSaver::loadedPopup', '*');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (navigator.serviceWorker) {
|
|
171
|
+
registerWorker().then(() => {
|
|
172
|
+
window.onmessage = onMessage;
|
|
173
|
+
messages.forEach(window.onmessage);
|
|
174
|
+
});
|
|
175
|
+
} else {
|
|
176
|
+
// FF can ping sw with fetch from a secure hidden iframe
|
|
177
|
+
// shouldn't really be possible?
|
|
178
|
+
keepAlive();
|
|
179
|
+
}
|
|
180
|
+
</script>
|