Browse Source

change file encoding

master
godo 6 months ago
parent
commit
119a2cf36f
  1. 46
      frontend/public/markdown/scripts/index.js
  2. 6
      frontend/public/text/js/base.js
  3. 127
      frontend/src/components/window/IframeFile.vue
  4. 18
      frontend/src/system/index.ts
  5. 9
      godo/files/os.go
  6. 42
      godo/files/pwdfile.go
  7. 3
      godo/libs/msg.go
  8. 79
      packages/word/src/main.ts

46
frontend/public/markdown/scripts/index.js

@ -344,19 +344,55 @@ const debouncedHandleKeyDown = (event) => {
saveData();
}
};
function isBase64(str) {
if (str === '' || str.trim() === '') {
return false;
}
try {
return btoa(atob(str)) == str;
} catch (err) {
return false;
}
}
function decodeBase64(base64String) {
// 将Base64字符串分成每64个字符一组
const padding = (base64String.length % 4) === 0 ? 0 : 4 - (base64String.length % 4);
base64String += '='.repeat(padding);
// 使用atob()函数解码Base64字符串
const binaryString = atob(base64String);
// 将二进制字符串转换为TypedArray
const bytes = new Uint8Array(binaryString.length);
for (let i = 0; i < binaryString.length; i++) {
bytes[i] = binaryString.charCodeAt(i);
}
// 将TypedArray转换为字符串
return new TextDecoder('utf-8').decode(bytes);
}
const eventHandler = (e) => {
const eventData = e.data
// if (eventData.type === 'start') {
// markdownTitle = '未命名文稿'
// }
if (eventData.type === 'start') {
markdownTitle = eventData.title || '未命名文稿'
return
}
// console.log(markdownTitle)
if (eventData.type === 'init') {
markdownTitle = eventData.title ? eventData.title : '未命名文稿'
const data = eventData.data
markdownTitle = data.title || '未命名文稿'
if (!data) {
return;
}
cherry.setMarkdown(atob(data.content));
let content = data.content;
if (isBase64(content)) {
content = decodeBase64(content);
} else if (content instanceof ArrayBuffer) {
content = new TextDecoder('utf-8').decode(content);
}
cherry.setMarkdown(content);
}
}
window.addEventListener('load', () => {

6
frontend/public/text/js/base.js

@ -915,18 +915,18 @@ const eventHandler = (e) => {
renameEditor({ name: eventData.title });
}
if (eventData.type === 'init') {
console.log(eventData)
//console.log(eventData)
//const data = JSON.parse(eventData.data)
const data = eventData.data
if (!data || !data.title) {
return;
}
console.log(data)
//console.log(data)
if(data.ext && data.ext != 'txt') {
//Editor.query().setName("extension", data.ext);
data.title = data.title + "." + data.ext;
}
console.log(data.title)
//console.log(data.title)
renameEditor({ name: data.title });
//console.log(data)
if (data.content) {

127
frontend/src/components/window/IframeFile.vue

@ -37,7 +37,7 @@ const storeRef = ref<HTMLIFrameElement | null>(null);
let hasInit = false;
const eventHandler = async (e: MessageEvent) => {
const eventData = e.data;
if (eventData.type == props.eventType) {
let data = JSON.parse(eventData.data);
let title = data.title;
@ -49,6 +49,9 @@ const eventHandler = async (e: MessageEvent) => {
if (data.ext) {
ext = data.ext;
}
if (title.indexOf('.' + ext) > -1) {
title = title.replace('.' + ext, "");
}
// console.log(ext)
// console.log(data)
if (win.config && win.config.path) {
@ -131,19 +134,19 @@ const eventHandler = async (e: MessageEvent) => {
// console.log(title);
title = title.split(SP).pop();
if (!content && win?.config.path) {
const header = {
pwd: ''
};
const filePwd = getSystemConfig().fileInputPwd
const pos = filePwd.findIndex((item: any) => item.path == win?.config.path)
//console.log('', win?.config.path, pos, filePwd);
const userType = getSystemConfig().userType
if (pos !== -1) {
header.pwd = userType == 'person' ? md5(filePwd[pos].pwd) : filePwd[pos].pwd
}
content = await sys?.fs.readFile(win?.config.path, header);
}
// if (!content && win?.config.path) {
// const header = {
// pwd: ''
// };
// const filePwd = getSystemConfig().fileInputPwd
// const pos = filePwd.findIndex((item: any) => item.path == win?.config.path)
// //console.log('', win?.config.path, pos, filePwd);
// const userType = getSystemConfig().userType
// if (pos !== -1) {
// header.pwd = userType == 'person' ? md5(filePwd[pos].pwd) : filePwd[pos].pwd
// }
// content = await sys?.fs.readFile(win?.config.path, header);
// }
content = toRaw(content);
if (content && content !== "") {
storeRef.value?.contentWindow?.postMessage(
@ -173,59 +176,59 @@ const eventHandler = async (e: MessageEvent) => {
const path = win?.config?.path;
//console.log(path,data)
const winMind = new BrowserWindow({
title:data.title,
title: data.title,
url: "/mind/index.html",
frame: true,
config: {
ext: 'mind',
path: path,
config: {
ext: 'mind',
path: path,
content: data.content
},
icon: "gallery",
width: 700,
height: 500,
x: 100,
y: 100,
//center: true,
minimizable: false,
resizable: true,
});
winMind.show()
}
else if (eventData.type == 'aiCreater') {
console.log('传递内容: ',eventData)
let postData:any = {}
if(eventData.data){
postData.content = eventData.data
}
if(eventData.title){
postData.title = eventData.title
},
icon: "gallery",
width: 700,
height: 500,
x: 100,
y: 100,
//center: true,
minimizable: false,
resizable: true,
});
winMind.show()
}
if(eventData.category){
postData.category = eventData.category
else if (eventData.type == 'aiCreater') {
console.log('传递内容: ', eventData)
let postData: any = {}
if (eventData.data) {
postData.content = eventData.data
}
if (eventData.title) {
postData.title = eventData.title
}
if (eventData.category) {
postData.category = eventData.category
}
//console.log(postData,eventData.action)
// AI
const res: any = await askAi(postData, eventData.action);
storeRef.value?.contentWindow?.postMessage(
{
type: 'aiReciver',
data: res,
action: eventData.action
},
"*"
);
}
//console.log(postData,eventData.action)
// AI
const res:any = await askAi(postData, eventData.action);
storeRef.value?.contentWindow?.postMessage(
{
type: 'aiReciver',
data: res,
action: eventData.action
},
"*"
);
}
// else if (eventData.type == 'aiReciver') {
// storeRef.value?.contentWindow?.postMessage(
// {
// type: eventData.type,
// data: '----AI-----',
// },
// "*"
// );
// }
// else if (eventData.type == 'aiReciver') {
// storeRef.value?.contentWindow?.postMessage(
// {
// type: eventData.type,
// data: '----AI-----',
// },
// "*"
// );
// }
};
//
const delFileInputPwd = async () => {

18
frontend/src/system/index.ts

@ -461,14 +461,14 @@ export class System {
pwd: ''
}
//判断文件是否需要输入密码
// if (fileStat.isPwd && path.indexOf('.exe') === -1) {
// const temp = await Dialog.showInputBox()
// if (temp.response !== 1) {
// return
// }
// // header.salt = filePwd.file.salt || 'vIf_wIUedciAd0nTm6qjJA=='
// header.pwd = temp?.inputPwd || ''
// }
if (fileStat.isPwd && path.indexOf('.exe') === -1) {
const temp = await Dialog.showInputBox()
if (temp.response !== 1) {
return
}
// header.salt = filePwd.file.salt || 'vIf_wIUedciAd0nTm6qjJA=='
header.pwd = temp?.inputPwd || ''
}
// 读取文件内容
const fileContent = await this.fs.readFile(path, header);
// if (fileContent === false && fileStat.isPwd) {
@ -482,7 +482,7 @@ export class System {
}
// header.salt = filePwd.file.salt || 'vIf_wIUedciAd0nTm6qjJA=='
header.pwd = temp?.inputPwd ? md5(temp?.inputPwd) : ''
const reOpen = await this.fs.readFile(path, header);
//const reOpen = await this.fs.readFile(path, header);
}
//用户文件加密密码存储
if (fileStat.isPwd) {

9
godo/files/os.go

@ -25,6 +25,7 @@ import (
"io/fs"
"os"
"path/filepath"
"regexp"
"strings"
"time"
)
@ -336,5 +337,13 @@ func IsPwdFile(fileData []byte) bool {
} else if fileData[0] != '@' || fileData[33] != '@' {
return false
}
// 提取中间的字符串
middleStr := string(fileData[1:33])
// 使用正则表达式验证中间的字符串是否为 MD5 加密的字符串
md5Regex := regexp.MustCompile(`^[a-fA-F0-9]{32}$`)
if !md5Regex.MatchString(middleStr) {
return false
}
return true
}

42
godo/files/pwdfile.go

@ -1,7 +1,6 @@
package files
import (
"encoding/base64"
"encoding/json"
"fmt"
"godo/libs"
@ -43,8 +42,8 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
libs.HTTPError(w, http.StatusInternalServerError, err.Error())
return
}
//log.Printf("fileData: %s", string(fileData))
configPwd, ishas := libs.GetConfig("filePwd")
//log.Printf("configPwd: %s", configPwd)
// 如果不是加密文件或者exe文件
if !ishas || strings.HasPrefix(string(fileData), "link::") {
// 没开启加密,直接明文写入
@ -66,17 +65,22 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
libs.HTTPError(w, http.StatusInternalServerError, "配置文件密码格式错误")
return
}
_, err = newFile.WriteString(fmt.Sprintf("@%s@", configPwdStr))
if err != nil {
libs.HTTPError(w, http.StatusInternalServerError, "密码写入失败")
return
}
// 拼接密码和加密后的数据
passwordPrefix := fmt.Sprintf("@%s@", configPwdStr)
// _, err = newFile.WriteString(fmt.Sprintf("@%s@", configPwdStr))
// if err != nil {
// libs.HTTPError(w, http.StatusInternalServerError, "密码写入失败")
// return
// }
entryData, err := libs.EncryptData(fileData, []byte(configPwdStr))
if err != nil {
libs.HTTPError(w, http.StatusInternalServerError, "文件加密失败")
return
}
_, err = newFile.Write(entryData)
// 将密码前缀和加密数据拼接成一个完整的字节切片
completeData := []byte(passwordPrefix + string(entryData))
// 一次性写入文件
_, err = newFile.Write(completeData)
if err != nil {
libs.HTTPError(w, http.StatusInternalServerError, "文件写入失败")
return
@ -123,8 +127,8 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
if !isPwd {
// 未加密文件,直接返回
content := base64.StdEncoding.EncodeToString(fileData)
res := libs.APIResponse{Message: "文件读取成功", Data: content}
//content := base64.StdEncoding.EncodeToString(fileData)
res := libs.APIResponse{Message: "文件读取成功", Data: fileData}
json.NewEncoder(w).Encode(res)
return
}
@ -134,18 +138,19 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
if Pwd == "" {
configPwd, ishas := libs.GetConfig("filePwd")
if !ishas {
libs.ErrorMsg(w, "未设置密码")
libs.Error(w, "未设置密码", "needPwd")
return
}
configPwdStr, ok := configPwd.(string)
if !ok {
libs.ErrorMsg(w, "后端配置文件密码格式错误")
libs.Error(w, "后端配置文件密码格式错误", "needPwd")
return
}
// 校验密码
if filePwd != configPwdStr {
res := libs.APIResponse{Message: "密码错误,请输入正确的密码", Code: -1, Error: "needPwd"}
json.NewEncoder(w).Encode(res)
libs.Error(w, "密码错误,请输入正确的密码", "errPwd")
// res := libs.APIResponse{Message: "密码错误,请输入正确的密码", Code: -1, Error: "needPwd"}
// json.NewEncoder(w).Encode(res)
return
}
decryptData, err := libs.DecryptData(fileData[34:], []byte(filePwd))
@ -153,8 +158,9 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
libs.ErrorMsg(w, err.Error())
return
}
content := base64.StdEncoding.EncodeToString(decryptData)
res := libs.APIResponse{Message: "加密文件读取成功", Data: content}
//content := base64.StdEncoding.EncodeToString(decryptData)
res := libs.APIResponse{Message: "加密文件读取成功", Data: decryptData}
json.NewEncoder(w).Encode(res)
return
} else {
@ -169,8 +175,8 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
libs.ErrorMsg(w, err.Error())
return
}
content := base64.StdEncoding.EncodeToString(decryptData)
res := libs.APIResponse{Message: "加密文件读取成功", Data: content}
//content := base64.StdEncoding.EncodeToString(decryptData)
res := libs.APIResponse{Message: "加密文件读取成功", Data: decryptData}
json.NewEncoder(w).Encode(res)
}
}

3
godo/libs/msg.go

@ -46,6 +46,9 @@ func ErrorMsg(w http.ResponseWriter, message string) {
func ErrorData(w http.ResponseWriter, data any, message string) {
WriteJSONResponse(w, APIResponse{Message: message, Data: data, Code: -1}, 200)
}
func Error(w http.ResponseWriter, message string, err string) {
WriteJSONResponse(w, APIResponse{Message: message, Error: err, Code: -1}, 200)
}
func SuccessMsg(w http.ResponseWriter, data any, message string) {
WriteJSONResponse(w, APIResponse{Message: message, Data: data, Code: 0}, 200)
}

79
packages/word/src/main.ts

@ -27,7 +27,7 @@ import { Signature } from './components/signature/Signature'
import { debounce, nextTick, scrollIntoView } from './utils'
import barcode1DPlugin from "./plugins/barcode1d"
import barcode2dPlugin from "./plugins/barcode2d"
import { floatingToolbarPlugin, changeAiTextarea} from "./plugins/floatingToolbar"
import { floatingToolbarPlugin, changeAiTextarea } from "./plugins/floatingToolbar"
import excelPlugin from "./plugins/excel"
import docxPlugin from './plugins/docx'
window.onload = function () {
@ -58,7 +58,7 @@ window.onload = function () {
instance.use(docxPlugin)
const docxFileInput: any = document.querySelector("#file-docx");
const excelFileInput: any = document.querySelector("#file-excel");
let wordTitle: any = ''
let godoWordTitle: any = ""
// cypress使用
Reflect.set(window, 'editor', instance)
@ -1172,7 +1172,7 @@ window.onload = function () {
function () {
const title = articleTitle.value
const category = articleType.value
if (title == '' || category == '') {
// alert()
// new Dialog({
@ -1213,7 +1213,7 @@ window.onload = function () {
// outlineLoader.classList.remove('hide')
// articleLoader.classList.add('hide')
break
case 'article':
case 'article':
watchArticle.classList.add('active-ai')
watchOutline.classList.remove('active-ai')
createArticleBtn?.classList.add('hide')
@ -1230,7 +1230,7 @@ window.onload = function () {
// 查看大纲
watchOutline.onclick = () => switchView('outline')
// 查看文章
watchArticle.onclick = () => switchView('article')
watchArticle.onclick = () => switchView('article')
// 生成文章
createArticleBtn.onclick = function () {
switchView('article')
@ -1248,7 +1248,7 @@ window.onload = function () {
// articleTextarea.value = AiResult.aiArticle
}
// 替换textarea内容
function changeAiArticleTextarea (data: string , type: string) {
function changeAiArticleTextarea(data: string, type: string) {
if (type == 'outline') {
outlineTextarea.value = data
outlineLoader.classList.add('hide')
@ -1950,11 +1950,11 @@ window.onload = function () {
name: "导出文档",
when: () => true,
callback: (command) => {
if (wordTitle == '') {
wordTitle = window.prompt("请输入文档标题");
if (godoWordTitle == '') {
godoWordTitle = window.prompt("请输入文档标题");
}
command.executeExportDocx({
fileName: wordTitle,
fileName: godoWordTitle,
isFile: true
});
},
@ -2077,16 +2077,17 @@ window.onload = function () {
};
reader.readAsArrayBuffer(file);
};
const saveData = () => {
if (wordTitle == '') {
wordTitle = window.prompt("请输入文档标题");
if (godoWordTitle == '') {
godoWordTitle = window.prompt("请输入文档标题");
}
console.log(godoWordTitle)
instance.command.executeExportDocx({
fileName: wordTitle,
fileName: godoWordTitle,
isFile: false
})
};
// 10. 快捷键注册
instance.register.shortcutList([
@ -2151,7 +2152,7 @@ window.onload = function () {
saveDom.addEventListener('click', () => {
saveData()
})
const base64ToArrayBuffer = (base64:any) => {
const base64ToArrayBuffer = (base64: any) => {
const binaryString = window.atob(base64);
const len = binaryString.length;
const bytes = new Uint8Array(len);
@ -2160,24 +2161,48 @@ window.onload = function () {
}
return bytes.buffer;
}
function isBase64(str: any) {
if (str === '' || str.trim() === '') {
return false;
}
try {
return btoa(atob(str)) == str;
} catch (err) {
return false;
}
}
const eventHandler = (e: any) => {
const eventData = e.data
// console.log('');
wordTitle = eventData.title ? eventData.title : '未命名文档'
//godoWordTitle = eventData.title ? eventData.title : '未命名文档'
if (eventData.type === 'start') {
godoWordTitle = eventData.title
return
}
if (eventData.type === 'init') {
const data = eventData.data
if (!data) {
if (!data || !data.title) {
return;
}
const buffer = base64ToArrayBuffer(data.content)
godoWordTitle = data.title
if (isBase64(data.content)) {
data.content = base64ToArrayBuffer(data.content)
}
//const buffer = base64ToArrayBuffer(data.content)
//console.log(buffer)
instance.command.executeImportDocx({
arrayBuffer: buffer,
});
if (data.content instanceof ArrayBuffer) {
instance.command.executeImportDocx({
arrayBuffer: data.content,
});
} else {
alert('导入失败')
}
return
} else if (eventData.type == 'aiReciver') {
console.log('接收到来自伏组件数据:', eventData);
}
if (eventData.type == 'aiReciver') {
//console.log('接收到来自伏组件数据:', eventData);
if (eventData.action == 'creation_leader') {
changeAiArticleTextarea(eventData.data, 'outline')
} else if (eventData.action == 'creation_builder') {
@ -2188,10 +2213,10 @@ window.onload = function () {
}
}
//window.addEventListener('load', () => {
window.parent.postMessage({ type: 'initSuccess' }, '*')
window.addEventListener('message', eventHandler)
window.parent.postMessage({ type: 'initSuccess' }, '*')
window.addEventListener('message', eventHandler)
//})
window.addEventListener('unload', () => {
window.removeEventListener('message', eventHandler)

Loading…
Cancel
Save