提交 76cffded 编写于 作者: Cano1997's avatar Cano1997

update: 添加重定向白名单校验

上级 a840c2a4
......@@ -7,6 +7,7 @@
<script lang="ts">
import { Vue, Component,Prop } from 'vue-property-decorator';
import { Subject } from 'rxjs';
import { safeRedirect } from '@/utils';
/**
* 表格列链接
*/
......@@ -192,7 +193,7 @@ export default class AppColumnLink extends Vue {
* @memberof AppColumnLink
*/
private openPopupApp(url: string): void {
window.open(url, '_blank');
safeRedirect(url, { type: '_blank'});
}
/**
......
......@@ -14,6 +14,7 @@
import { Vue, Component, Prop, Model, Emit } from "vue-property-decorator";
import { Subject } from "rxjs";
import { Environment } from '@/environments/environment';
import { safeRedirect } from "@/utils";
@Component({
})
......@@ -66,7 +67,7 @@ export default class AppHeaderMenus extends Vue {
* @memberof AppHeaderMenus
*/
public openWindow(menu:any){
window.open(menu.url, '_blank');
safeRedirect(menu.url, { type: '_blank'});
}
......
......@@ -33,6 +33,7 @@
import { Vue, Component, Prop, Watch, Provide } from 'vue-property-decorator';
import { Environment } from '@/environments/environment';
import { Subject, Unsubscribable } from 'rxjs';
import { safeRedirect } from '@/utils';
@Component({})
export default class AppImagePreview extends Vue {
......@@ -167,7 +168,7 @@ export default class AppImagePreview extends Vue {
* @memberof AppImagePreview
*/
public onDownload(file: any) {
window.open(file.url);
safeRedirect(file.url, { type: '_blank'});
}
/**
......
......@@ -65,6 +65,7 @@
import { Vue, Component, Prop, Watch, Provide } from 'vue-property-decorator';
import { Environment } from '@/environments/environment';
import { Subject, Unsubscribable } from 'rxjs';
import { safeRedirect } from '@/utils';
@Component({})
export default class AppImageUpload extends Vue {
......@@ -455,7 +456,7 @@ export default class AppImageUpload extends Vue {
* @memberof AppImageUpload
*/
public onDownload(file: any) {
window.open(file.url);
safeRedirect(file.url, { type: '_blank'});
}
/**
......
......@@ -87,6 +87,7 @@
import {Vue, Component, Prop, Model, Emit} from "vue-property-decorator";
import {Environment} from '@/environments/environment';
import moment from 'moment';
import { safeRedirect } from '@/utils';
@Component({})
export default class AppMessagePopover extends Vue {
......@@ -176,7 +177,7 @@ export default class AppMessagePopover extends Vue {
const baseUrl:any = Environment.BaseUrl;
const openUrl:any = baseUrl + `/wfcore/mytasks/${data.processDefinitionKey}/web/${data.processInstanceBusinessKey}/usertasks/${data.taskDefinitionKey}`;
// 打开新窗口
window.open(openUrl,'_blank');
safeRedirect(openUrl, { type: '_blank'});
}
/**
......
......@@ -58,7 +58,7 @@
<script lang = 'ts'>
import { Component, Vue, Prop, Model, Watch } from 'vue-property-decorator';
import { Subject } from 'rxjs';
import { AppModal } from '@/utils';
import { AppModal, safeRedirect } from '@/utils';
@Component({
})
......@@ -585,7 +585,7 @@ export default class AppPicker extends Vue {
* @memberof AppPicker
*/
private openPopupApp(url: string): void {
window.open(url, '_blank');
safeRedirect(url, { type: '_blank'});
}
/**
......
......@@ -10,6 +10,7 @@ import { Environment } from '@/environments/environment';
import { CreateElement } from 'vue';
import { Subject, Unsubscribable } from 'rxjs';
import EntityService from '@/service/entity-service';
import { safeRedirect } from '@/utils';
@Component({
})
......@@ -131,7 +132,7 @@ export default class AppUploadFileInfo extends Vue {
* @memberof AppUploadFileInfo
*/
public onDownload(file: any) {
window.open(file.url);
safeRedirect(file.url, { type: '_blank'});
}
}
......
......@@ -64,6 +64,7 @@
import draggable from "vuedraggable";
import EntityService from '@/service/entity-service';
import { Vue,Component,Provide,Watch,Prop,Model } from "vue-property-decorator";
import { safeRedirect } from '@/utils';
// tslint:disable-next-line:max-classes-per-file
@Component({
......@@ -219,7 +220,7 @@ export default class ContextMenuDrag extends Vue {
let params: any = {};
params.model = this.selectlist;
const put: Promise<any> = this.entityService.updateChooseApp(null,params);
window.location.href = item.addr;
safeRedirect(item.addr, { type: 'href' });
}else{
this.$message.info((this.$t('components.contextMenuDrag.noFind') as string));
}
......
......@@ -72,6 +72,7 @@ import { Unsubscribable } from 'rxjs';
import { Environment } from '@/environments/environment';
import { encode } from "js-base64";
import EntityService from '@/service/entity-service';
import { safeRedirect } from '@/utils';
@Component({})
export default class DiskFileUpload extends Vue {
......@@ -623,7 +624,7 @@ export default class DiskFileUpload extends Vue {
const name = typeof item.name == "string" ? item.name : JSON.stringify(item.name);
const editUrl = '/net-disk/editview/' + this.getFolder() + '/' + id + '/' + name + '?authcode=' + item.authcode;
// TODO:暂时用window.open
window.open(editUrl);
safeRedirect(editUrl, { type: '_blank'});
}
/**
......
......@@ -12,3 +12,4 @@ export { UIActionTool } from './uiaction-tool/uiaction-tool';
export { LoadAppData } from './load-app-data/load-app-data';
export { Interceptors } from './interceptor/interceptor';
export { StudioActionUtil } from './studio-action/StudioActionUtil';
export { safeRedirect } from './redirect-util/redirect-util';
......@@ -5,6 +5,7 @@ import i18n from '@/locale';
import { Environment } from '@/environments/environment';
import { Http } from '../http/http';
import { Util } from '../util/util';
import { safeRedirect } from '..';
/**
* 拦截器
......@@ -171,7 +172,7 @@ export class Interceptors {
}
loginurl = `${loginurl}${_url}`;
window.location.href = loginurl;
safeRedirect(loginurl, { type: 'href' });
} else {
if (Object.is(this.router.currentRoute.name, 'login')) {
return;
......
import { Environment } from '@/environments/environment';
/**
* @description 计算跳转路径是否在白名单中
* @param {string} url
* @returns {*} {boolean}
*/
const isAllowed = (url: string): boolean => {
if (!url) return false;
const { protocol, hostname, origin } = new URL(url, window.location.origin);
// 非http、https、blob:协议直接拦截
if (!['blob:', 'https:', 'http:'].includes(protocol)) return false;
// 相对路径直接放过
if (window.location.origin === origin) {
return true;
}
const allowList: string[] = Environment.redirectWhiteList.split(',');
return allowList.some(rule => {
if (typeof rule === 'string') {
if (rule.includes('*')) {
const reg = new RegExp(`^${rule.replace(/\*/g, '[^/]+')}$`);
return reg.test(hostname);
}
return rule === `${protocol}//${hostname}`;
}
return (rule as RegExp).test(url);
});
};
/**
* 唯一重定向出口
* @param url 目标地址
* @param fallback 不合法时回退地址,默认当前页
*/
export function safeRedirect(
url: string,
options: any = {},
): Window | null | undefined {
try {
if (isAllowed(url)) {
const { type = '_blank' } = options;
if (type === 'href') {
window.location.href = url;
} else {
return window.open(url, type);
}
} else {
console.error(`重定向路径${url}不在白名单中,请确认是否正确!`);
}
} catch {
console.error(`重定向路径${url}不在白名单中,请确认是否正确!`);
}
}
import Vue from 'vue';
import { Http } from '@/utils';
import { Http, safeRedirect } from '@/utils';
import { Environment } from '@/environments/environment';
import { on } from '@/utils/dom/dom';
......@@ -92,7 +92,7 @@ export class StudioActionUtil {
const config: any = await this.getConfig(viewName);
if (config) {
const context: string = `视图模块:${config.viewmodule}\n视图标识:${config.viewname}\n视图类型:${config.viewtype}\n`;
window.open(`${Environment.ProjectUrl}/issues/new?issue[title]=${encodeURIComponent('问题')}&issue[description]=${encodeURIComponent(context)}`, '_blank');
safeRedirect(`${Environment.ProjectUrl}/issues/new?issue[title]=${encodeURIComponent('问题')}&issue[description]=${encodeURIComponent(context)}`, { type: '_blank'});
}
}
......@@ -123,7 +123,10 @@ export class StudioActionUtil {
console.log("打开sln未支持");
// this.studioWin = window.open(`${Environment.StudioUrl}?ov=${encodeURIComponent(JSON.stringify(params))}#/common_slnindex/srfkeys=${Environment.SlnId}/sysdesign_psdevslnsysmodeltreeexpview/srfkey=${Environment.SysId}`, '_blank');
}else{
this.studioWin = window.open(`${Environment.StudioUrl}?ov=${encodeURIComponent(JSON.stringify(params))}#/common_mosindex/srfkeys=${Environment.SysId}`, '_blank');
const win = safeRedirect(`${Environment.StudioUrl}?ov=${encodeURIComponent(JSON.stringify(params))}#/common_mosindex/srfkeys=${Environment.SysId}`, { type: '_blank'});
if (win) {
this.studioWin = win;
}
}
}
}
......
import qs from 'qs';
import { Route } from 'vue-router';
import Schema from "async-validator";
import { safeRedirect } from '..';
/**
* 平台工具类
......@@ -59,7 +60,7 @@ export class Util {
*/
public static processResult(o: any = {}): void {
if (o.url != null && o.url !== '') {
window.location.href = o.url;
safeRedirect(o.url, { type: 'href' });
}
if (o.code != null && o.code !== '') {
// tslint:disable-next-line:no-eval
......@@ -80,7 +81,7 @@ export class Util {
* @memberof Util
*/
public static download(url: string): void {
window.open(url, '_blank');
safeRedirect(url, { type: '_blank'});
}
/**
......
Markdown 格式
0% or
您添加了 0 到此讨论。请谨慎行事。
先完成此消息的编辑!
想要评论请 注册