🎨 粘贴安全策略提示.

This commit is contained in:
lijiahangmax
2024-03-24 23:07:16 +08:00
parent cf188451dd
commit fade56b12a
22 changed files with 106 additions and 40 deletions

View File

@@ -1,3 +1,3 @@
mv ../../orion-ops-launch/target/orion-ops-launch.jar ./
mv ../../orion-ops-ui/dist ./dist
docker build -t orion-ops-pro:1.0.2 .
docker build -t orion-ops-pro:1.0.3 .

View File

@@ -2,18 +2,20 @@
## v1.0.3
`2024-03-2` `release`
`2024-03-24` `release`
* 🚀 升级 `arco design``2.55.0`
* 🐞 修复 新创建的用户登录会跳转到 **404**
* 🐞 修复 分配菜单模态框没有子菜单不显示的问题
* 🐞 修复 终端无法粘贴
* 🐞 修复 `工作台` `快捷操作` 会展示隐藏的菜单
* 🐞 修复 工作台页面快捷操作面板会展示隐藏的菜单
* 🐞 修复 主机终端无法粘贴
* 🐞 修复 卡片列表组件控制台 warn 提示
* 🐞 修复 关闭终端时控制台提示 handleResize 错误信息
* 🔨 修改 系统菜单渲染逻辑 (移除 JSX 构建时不会提示 JSX.IntrinsicElements)
[如何升级](/about/update.md?id=_v103)
## v1.0.2
## v1.0.3
`2024-03-22` `release`

View File

@@ -12,3 +12,7 @@
* 资产授权 UI 改版
* RDP 远程桌面
* 接入 config 后端动态配置
## 已知问题 🐞
* 顶部菜单折叠宽度计算有问题 (arco 框架内问题)

View File

@@ -26,6 +26,8 @@ import java.util.List;
@Component
public class SftpListHandler extends AbstractTerminalHandler<SftpListRequest> {
private static final String HOME_PATH = "~";
@Override
public void handle(WebSocketSession channel, SftpListRequest payload) {
// 获取会话
@@ -37,7 +39,7 @@ public class SftpListHandler extends AbstractTerminalHandler<SftpListRequest> {
List<SftpFileVO> list = Lists.empty();
try {
// 空目录则直接获取 home 目录
if (Strings.isBlank(path)) {
if (HOME_PATH.equals(path)) {
path = session.getHome();
}
// 文件列表

View File

@@ -272,7 +272,9 @@ export default class LogAppender implements ILogAppender {
.filter(Boolean)
.forEach(s => s.dispose());
// 卸载终端
s.terminal?.dispose();
setTimeout(() => {
s.terminal?.dispose();
}, 300);
} catch (e) {
// 卸载可能会报错
}

View File

@@ -49,7 +49,10 @@
'field-value',
field.ellipsis ? 'field-value-ellipsis' : ''
]">
<slot :name="field.slotName" :record="item" :index="index" :key="item[key as string]">
<slot :name="field.slotName"
:record="item"
:index="index"
:rowKey="item[rowKey as string]">
<a-tooltip v-if="field.tooltip" :content="item[field.dataIndex]">
<span v-if="field.render" v-html="field.render({ record: item, index })" />
<span v-else>{{ item[field.dataIndex] }}</span>
@@ -87,7 +90,7 @@
const props = defineProps<CardProps & {
index: number,
item: CardRecord
item: CardRecord,
}>();
const emits = defineEmits(['emitter']);

View File

@@ -29,7 +29,7 @@
</a-col>
<!-- 数据卡片 -->
<a-col v-for="(item, index) in list"
:key="item[key]"
:key="item[rowKey]"
v-bind="cardLayoutCols"
:class="{ 'disabled-col': item.disabled === true }">
<!-- 右键菜单 -->
@@ -41,12 +41,18 @@
@emitter="dispatchEmitter">
<!-- 自定义插槽 -->
<template v-for="slot in Object.keys($slots)" :key="slot" #[slot]>
<slot :name="slot" :record="item" :index="index" :key="item[key]" />
<slot :name="slot"
:record="item"
:index="index"
:rowKey="item[rowKey]" />
</template>
</card-item>
<!-- 右键菜单 -->
<template v-if="contextMenu" #content>
<slot name="contextMenu" :record="item" :index="index" :key="item[key]" />
<slot name="contextMenu"
:record="item"
:index="index"
:rowKey="item[rowKey]" />
</template>
</a-dropdown>
</a-col>
@@ -82,7 +88,7 @@
import useEmitter from '@/hooks/emitter';
const props = withDefaults(defineProps<CardProps>(), {
key: 'id',
rowKey: 'id',
pagination: false,
loading: false,
cardHeight: '100%',

View File

@@ -4,7 +4,7 @@ import type { CardFieldConfig, CardPosition, CardRecord, ColResponsiveValue, Han
// 卡片属性
export interface CardProps {
key?: string;
rowKey?: string;
pagination?: PaginationProps | boolean;
loading?: boolean;
fieldConfig?: CardFieldConfig;

View File

@@ -47,7 +47,7 @@
</a-watermark>
</a-layout-content>
<!-- 页脚 -->
<footer v-if="visibleFooter" />
<app-footer v-if="visibleFooter" />
</a-layout>
</a-layout>
</a-layout>
@@ -61,8 +61,8 @@
import { toggleDrawerMenuKey } from '@/types/symbol';
import PageLayout from './page-layout.vue';
import NavBar from '@/components/app/navbar/index.vue';
import Footer from '@/components/app/footer/index.vue';
import TabBar from '@/components/app/tab-bar/index.vue';
import AppFooter from '@/components/app/app-footer/index.vue';
import SystemMenuTree from '@/components/system/menu/tree/index.vue';
const appStore = useAppStore();

View File

@@ -1,5 +1,10 @@
const debug = import.meta.env.MODE !== 'production';
// 当前环境是否为安全环境
export const isSecureEnvironment = (() => {
return window.location.protocol === 'https:' || window.location.hostname === 'localhost';
})();
// http base url
export const httpBaseUrl = (() => {
const configBase = import.meta.env.VITE_API_BASE_URL;

View File

@@ -8,16 +8,16 @@
<div class="logo-text">Orion Ops Pro</div>
</div>
<!-- 左侧 banner -->
<LoginBanner />
<login-banner />
<!-- 主体部分 -->
<div class="content">
<div class="content-inner">
<!-- 登录表单 -->
<LoginForm />
<login-form />
</div>
<!-- 页脚 -->
<div class="footer">
<Footer />
<app-footer />
</div>
</div>
</div>
@@ -26,9 +26,9 @@
<script lang="ts" setup>
import { Notification } from '@arco-design/web-vue';
import { reLoginTipsKey } from '@/types/symbol';
import Footer from '@/components/app/footer/index.vue';
import LoginBanner from './components/banner.vue';
import LoginForm from './components/login-form.vue';
import AppFooter from '@/components/app/app-footer/index.vue';
// 登录提示
const tips = window.sessionStorage.getItem(reLoginTipsKey);

View File

@@ -4,7 +4,7 @@
<div class="top-side">
<!-- 提示 -->
<div class="panel">
<Banner />
<banner />
</div>
</div>
<div class="row-wrapper">

View File

@@ -13,7 +13,12 @@
</div>
<!-- 描述 -->
<div class="block-form-item-desc">
{{ desc }}
<template v-if="desc">
{{ desc }}
</template>
<template v-else>
<slot name="desc" />
</template>
</div>
</div>
</a-col>
@@ -29,13 +34,14 @@
defineProps<{
label: string,
desc: string,
desc?: string,
}>();
</script>
<style lang="less" scoped>
.block-form-item-wrapper {
width: 458px;
height: 100%;
min-height: 64px;
border-radius: 4px;

View File

@@ -8,6 +8,12 @@
</div>
<!-- 提示 -->
<a-alert class="mb16">修改后会立刻保存, 立即生效 (无需刷新页面)</a-alert>
<!-- 非安全环境提示 -->
<a-alert v-if="!isSecureEnvironment"
type="warning"
class="mb16">
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
</a-alert>
<!-- 内容区域 -->
<div class="terminal-setting-body block-body setting-body">
<a-form class="terminal-setting-form"
@@ -52,6 +58,7 @@
import { useTerminalStore } from '@/store';
import { TerminalPreferenceItem } from '@/store/modules/terminal';
import { ActionBarItems } from '../../../types/terminal.const';
import { isSecureEnvironment } from '@/utils/env';
import IconActions from '../../layout/icon-actions.vue';
const { preference, updateTerminalPreference } = useTerminalStore();

View File

@@ -8,6 +8,12 @@
</div>
<!-- 提示 -->
<a-alert class="mb16">修改后会立刻保存, 重新打开终端后生效 (无需刷新页面)</a-alert>
<!-- 非安全环境提示 -->
<a-alert v-if="!isSecureEnvironment"
type="warning"
class="mb16">
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
</a-alert>
<!-- 内容区域 -->
<div class="terminal-setting-body block-body setting-body">
<!-- 功能项 -->
@@ -84,6 +90,7 @@
import { useTerminalStore } from '@/store';
import { TerminalPreferenceItem } from '@/store/modules/terminal';
import { ActionBarItems } from '../../../types/terminal.const';
import { isSecureEnvironment } from '@/utils/env';
const { preference, updateTerminalPreference } = useTerminalStore();

View File

@@ -8,6 +8,12 @@
</div>
<!-- 提示 -->
<a-alert class="mb16">修改后会立刻保存, 刷新页面后生效</a-alert>
<!-- 非安全环境提示 -->
<a-alert v-if="!isSecureEnvironment"
type="warning"
class="mb16">
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
</a-alert>
<!-- 内容区域 -->
<div class="terminal-setting-body setting-body">
<a-row class="mb16" align="stretch" :gutter="16">
@@ -40,23 +46,29 @@
<a-switch type="round"
v-model="formModel.copyAutoTrim" />
</block-setting-item>
<!-- 粘贴去除空格 -->
<block-setting-item label="粘贴去除空格" desc="粘贴文本前自动删除尾部空格 如: 命令输入框, 命令编辑器, 右键粘贴, 粘贴按钮, 右键菜单粘贴, 自定义粘贴快捷键 (内置粘贴快捷键因浏览器限制不会去除)">
<a-switch type="round"
v-model="formModel.pasteAutoTrim" />
</block-setting-item>
</a-row>
<a-row class="mb16" align="stretch" :gutter="16">
<!-- 右键粘贴 -->
<block-setting-item label="右键粘贴" desc="右键自动粘贴, 启用后需要关闭右键菜单 (若开启了右键选中词条, 有选中的文本时, 右键粘贴无效)">
<a-switch type="round"
v-model="formModel.rightClickPaste" />
</block-setting-item>
<!-- 启用右键菜单 -->
<block-setting-item label="启用右键菜单" desc="右键终端将打开自定义菜单, 启用后需要关闭右键粘贴">
<a-switch type="round"
v-model="formModel.enableRightClickMenu" />
</block-setting-item>
</a-row>
<a-row class="mb16" align="stretch" :gutter="16">
<!-- 右键粘贴 -->
<block-setting-item label="右键粘贴"
desc="启用右键自动粘贴需要关闭右键菜单. 如果启用右键选中词条且选中有文本时, 右键粘贴无效. 因浏览器安全策略限制, 此功能需要在 HTTPS 环境下使用">
<a-switch type="round"
v-model="formModel.rightClickPaste" />
</block-setting-item>
<!-- 粘贴去除空格 -->
<block-setting-item label="粘贴去除空格"
desc="粘贴文本前自动删除尾部空格 如: 命令输入框, 命令编辑器, 右键粘贴, 粘贴按钮, 右键菜单粘贴, 自定义粘贴快捷键. 默认粘贴快捷键无法去除空格">
<a-switch type="round"
v-model="formModel.pasteAutoTrim" />
<template #desc>
</template>
</block-setting-item>
</a-row>
<a-row class="mb16" align="stretch" :gutter="16">
<!-- 启用响铃 -->
@@ -87,6 +99,7 @@
import { ref, watch } from 'vue';
import { useTerminalStore } from '@/store';
import { TerminalPreferenceItem } from '@/store/modules/terminal';
import { isSecureEnvironment } from '@/utils/env';
import BlockSettingItem from '../block-setting-item.vue';
const { preference, updateTerminalPreference } = useTerminalStore();

View File

@@ -10,6 +10,12 @@
<div class="terminal-setting-body setting-body">
<!-- 提示 -->
<a-alert class="mb16">点击保存按钮后需要刷新页面生效 (恢复默认配置后也需要点击保存按钮) (设置时需要避免与浏览器内置快捷键冲突)</a-alert>
<!-- 非安全环境提示 -->
<a-alert v-if="!isSecureEnvironment"
type="warning"
class="mb16">
当前环境非 HTTPS 环境, 因浏览器安全策略限制, '粘贴' 功能无法使用
</a-alert>
<a-space class="action-container" size="mini">
<!-- 是否启用 -->
<a-switch v-model="value"
@@ -39,6 +45,7 @@
<script lang="ts" setup>
import { computed } from 'vue';
import { isSecureEnvironment } from '@/utils/env';
const props = defineProps<{
enabled: boolean

View File

@@ -170,11 +170,11 @@
// 连接成功回调
const connectCallback = () => {
loadFiles(undefined);
loadFiles('~');
};
// 加载文件列表
const loadFiles = (path: string | undefined) => {
const loadFiles = (path: string) => {
setTableLoading(true);
session.value?.list(path);
};

View File

@@ -46,7 +46,7 @@ export default class SftpSession implements ISftpSession {
}
// 查询文件列表
list(path: string | undefined) {
list(path: string) {
this.channel.send(InputProtocol.SFTP_LIST, {
sessionId: this.sessionId,
showHiddenFile: ~~this.showHiddenFile,

View File

@@ -248,7 +248,9 @@ export default class SshSession implements ISshSession {
.filter(Boolean)
.forEach(s => s.dispose());
// 卸载终端
this.inst.dispose();
setTimeout(() => {
this.inst.dispose();
}, 300);
} catch (e) {
// 卸载可能会报错
}

View File

@@ -324,7 +324,7 @@ export interface ISftpSession extends ITerminalSession {
// 设置显示隐藏文件
setShowHiddenFile: (show: boolean) => void;
// 查询文件列表
list: (path: string | undefined) => void;
list: (path: string) => void;
// 创建文件夹
mkdir: (path: string) => void;
// 创建文件