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(); 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 eventHandler = (e) => {
const eventData = e.data const eventData = e.data
// if (eventData.type === 'start') { if (eventData.type === 'start') {
// markdownTitle = '未命名文稿' markdownTitle = eventData.title || '未命名文稿'
// } return
}
// console.log(markdownTitle) // console.log(markdownTitle)
if (eventData.type === 'init') { if (eventData.type === 'init') {
markdownTitle = eventData.title ? eventData.title : '未命名文稿'
const data = eventData.data const data = eventData.data
markdownTitle = data.title || '未命名文稿'
if (!data) { if (!data) {
return; 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', () => { window.addEventListener('load', () => {

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

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

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

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

18
frontend/src/system/index.ts

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

9
godo/files/os.go

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

42
godo/files/pwdfile.go

@ -1,7 +1,6 @@
package files package files
import ( import (
"encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
"godo/libs" "godo/libs"
@ -43,8 +42,8 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
libs.HTTPError(w, http.StatusInternalServerError, err.Error()) libs.HTTPError(w, http.StatusInternalServerError, err.Error())
return return
} }
//log.Printf("fileData: %s", string(fileData))
configPwd, ishas := libs.GetConfig("filePwd") configPwd, ishas := libs.GetConfig("filePwd")
//log.Printf("configPwd: %s", configPwd)
// 如果不是加密文件或者exe文件 // 如果不是加密文件或者exe文件
if !ishas || strings.HasPrefix(string(fileData), "link::") { if !ishas || strings.HasPrefix(string(fileData), "link::") {
// 没开启加密,直接明文写入 // 没开启加密,直接明文写入
@ -66,17 +65,22 @@ func HandleWriteFile(w http.ResponseWriter, r *http.Request) {
libs.HTTPError(w, http.StatusInternalServerError, "配置文件密码格式错误") libs.HTTPError(w, http.StatusInternalServerError, "配置文件密码格式错误")
return return
} }
_, err = newFile.WriteString(fmt.Sprintf("@%s@", configPwdStr)) // 拼接密码和加密后的数据
if err != nil { passwordPrefix := fmt.Sprintf("@%s@", configPwdStr)
libs.HTTPError(w, http.StatusInternalServerError, "密码写入失败") // _, err = newFile.WriteString(fmt.Sprintf("@%s@", configPwdStr))
return // if err != nil {
} // libs.HTTPError(w, http.StatusInternalServerError, "密码写入失败")
// return
// }
entryData, err := libs.EncryptData(fileData, []byte(configPwdStr)) entryData, err := libs.EncryptData(fileData, []byte(configPwdStr))
if err != nil { if err != nil {
libs.HTTPError(w, http.StatusInternalServerError, "文件加密失败") libs.HTTPError(w, http.StatusInternalServerError, "文件加密失败")
return return
} }
_, err = newFile.Write(entryData) // 将密码前缀和加密数据拼接成一个完整的字节切片
completeData := []byte(passwordPrefix + string(entryData))
// 一次性写入文件
_, err = newFile.Write(completeData)
if err != nil { if err != nil {
libs.HTTPError(w, http.StatusInternalServerError, "文件写入失败") libs.HTTPError(w, http.StatusInternalServerError, "文件写入失败")
return return
@ -123,8 +127,8 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
if !isPwd { if !isPwd {
// 未加密文件,直接返回 // 未加密文件,直接返回
content := base64.StdEncoding.EncodeToString(fileData) //content := base64.StdEncoding.EncodeToString(fileData)
res := libs.APIResponse{Message: "文件读取成功", Data: content} res := libs.APIResponse{Message: "文件读取成功", Data: fileData}
json.NewEncoder(w).Encode(res) json.NewEncoder(w).Encode(res)
return return
} }
@ -134,18 +138,19 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
if Pwd == "" { if Pwd == "" {
configPwd, ishas := libs.GetConfig("filePwd") configPwd, ishas := libs.GetConfig("filePwd")
if !ishas { if !ishas {
libs.ErrorMsg(w, "未设置密码") libs.Error(w, "未设置密码", "needPwd")
return return
} }
configPwdStr, ok := configPwd.(string) configPwdStr, ok := configPwd.(string)
if !ok { if !ok {
libs.ErrorMsg(w, "后端配置文件密码格式错误") libs.Error(w, "后端配置文件密码格式错误", "needPwd")
return return
} }
// 校验密码 // 校验密码
if filePwd != configPwdStr { if filePwd != configPwdStr {
res := libs.APIResponse{Message: "密码错误,请输入正确的密码", Code: -1, Error: "needPwd"} libs.Error(w, "密码错误,请输入正确的密码", "errPwd")
json.NewEncoder(w).Encode(res) // res := libs.APIResponse{Message: "密码错误,请输入正确的密码", Code: -1, Error: "needPwd"}
// json.NewEncoder(w).Encode(res)
return return
} }
decryptData, err := libs.DecryptData(fileData[34:], []byte(filePwd)) 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()) libs.ErrorMsg(w, err.Error())
return 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) json.NewEncoder(w).Encode(res)
return return
} else { } else {
@ -169,8 +175,8 @@ func HandleReadFile(w http.ResponseWriter, r *http.Request) {
libs.ErrorMsg(w, err.Error()) libs.ErrorMsg(w, err.Error())
return return
} }
content := base64.StdEncoding.EncodeToString(decryptData) //content := base64.StdEncoding.EncodeToString(decryptData)
res := libs.APIResponse{Message: "加密文件读取成功", Data: content} res := libs.APIResponse{Message: "加密文件读取成功", Data: decryptData}
json.NewEncoder(w).Encode(res) 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) { func ErrorData(w http.ResponseWriter, data any, message string) {
WriteJSONResponse(w, APIResponse{Message: message, Data: data, Code: -1}, 200) 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) { func SuccessMsg(w http.ResponseWriter, data any, message string) {
WriteJSONResponse(w, APIResponse{Message: message, Data: data, Code: 0}, 200) 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 { debounce, nextTick, scrollIntoView } from './utils'
import barcode1DPlugin from "./plugins/barcode1d" import barcode1DPlugin from "./plugins/barcode1d"
import barcode2dPlugin from "./plugins/barcode2d" import barcode2dPlugin from "./plugins/barcode2d"
import { floatingToolbarPlugin, changeAiTextarea} from "./plugins/floatingToolbar" import { floatingToolbarPlugin, changeAiTextarea } from "./plugins/floatingToolbar"
import excelPlugin from "./plugins/excel" import excelPlugin from "./plugins/excel"
import docxPlugin from './plugins/docx' import docxPlugin from './plugins/docx'
window.onload = function () { window.onload = function () {
@ -58,7 +58,7 @@ window.onload = function () {
instance.use(docxPlugin) instance.use(docxPlugin)
const docxFileInput: any = document.querySelector("#file-docx"); const docxFileInput: any = document.querySelector("#file-docx");
const excelFileInput: any = document.querySelector("#file-excel"); const excelFileInput: any = document.querySelector("#file-excel");
let wordTitle: any = '' let godoWordTitle: any = ""
// cypress使用 // cypress使用
Reflect.set(window, 'editor', instance) Reflect.set(window, 'editor', instance)
@ -1172,7 +1172,7 @@ window.onload = function () {
function () { function () {
const title = articleTitle.value const title = articleTitle.value
const category = articleType.value const category = articleType.value
if (title == '' || category == '') { if (title == '' || category == '') {
// alert() // alert()
// new Dialog({ // new Dialog({
@ -1213,7 +1213,7 @@ window.onload = function () {
// outlineLoader.classList.remove('hide') // outlineLoader.classList.remove('hide')
// articleLoader.classList.add('hide') // articleLoader.classList.add('hide')
break break
case 'article': case 'article':
watchArticle.classList.add('active-ai') watchArticle.classList.add('active-ai')
watchOutline.classList.remove('active-ai') watchOutline.classList.remove('active-ai')
createArticleBtn?.classList.add('hide') createArticleBtn?.classList.add('hide')
@ -1230,7 +1230,7 @@ window.onload = function () {
// 查看大纲 // 查看大纲
watchOutline.onclick = () => switchView('outline') watchOutline.onclick = () => switchView('outline')
// 查看文章 // 查看文章
watchArticle.onclick = () => switchView('article') watchArticle.onclick = () => switchView('article')
// 生成文章 // 生成文章
createArticleBtn.onclick = function () { createArticleBtn.onclick = function () {
switchView('article') switchView('article')
@ -1248,7 +1248,7 @@ window.onload = function () {
// articleTextarea.value = AiResult.aiArticle // articleTextarea.value = AiResult.aiArticle
} }
// 替换textarea内容 // 替换textarea内容
function changeAiArticleTextarea (data: string , type: string) { function changeAiArticleTextarea(data: string, type: string) {
if (type == 'outline') { if (type == 'outline') {
outlineTextarea.value = data outlineTextarea.value = data
outlineLoader.classList.add('hide') outlineLoader.classList.add('hide')
@ -1950,11 +1950,11 @@ window.onload = function () {
name: "导出文档", name: "导出文档",
when: () => true, when: () => true,
callback: (command) => { callback: (command) => {
if (wordTitle == '') { if (godoWordTitle == '') {
wordTitle = window.prompt("请输入文档标题"); godoWordTitle = window.prompt("请输入文档标题");
} }
command.executeExportDocx({ command.executeExportDocx({
fileName: wordTitle, fileName: godoWordTitle,
isFile: true isFile: true
}); });
}, },
@ -2077,16 +2077,17 @@ window.onload = function () {
}; };
reader.readAsArrayBuffer(file); reader.readAsArrayBuffer(file);
}; };
const saveData = () => { const saveData = () => {
if (wordTitle == '') { if (godoWordTitle == '') {
wordTitle = window.prompt("请输入文档标题"); godoWordTitle = window.prompt("请输入文档标题");
} }
console.log(godoWordTitle)
instance.command.executeExportDocx({ instance.command.executeExportDocx({
fileName: wordTitle, fileName: godoWordTitle,
isFile: false isFile: false
}) })
}; };
// 10. 快捷键注册 // 10. 快捷键注册
instance.register.shortcutList([ instance.register.shortcutList([
@ -2151,7 +2152,7 @@ window.onload = function () {
saveDom.addEventListener('click', () => { saveDom.addEventListener('click', () => {
saveData() saveData()
}) })
const base64ToArrayBuffer = (base64:any) => { const base64ToArrayBuffer = (base64: any) => {
const binaryString = window.atob(base64); const binaryString = window.atob(base64);
const len = binaryString.length; const len = binaryString.length;
const bytes = new Uint8Array(len); const bytes = new Uint8Array(len);
@ -2160,24 +2161,48 @@ window.onload = function () {
} }
return bytes.buffer; 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 eventHandler = (e: any) => {
const eventData = e.data const eventData = e.data
// console.log(''); // console.log('');
wordTitle = eventData.title ? eventData.title : '未命名文档' //godoWordTitle = eventData.title ? eventData.title : '未命名文档'
if (eventData.type === 'start') {
godoWordTitle = eventData.title
return
}
if (eventData.type === 'init') { if (eventData.type === 'init') {
const data = eventData.data const data = eventData.data
if (!data) { if (!data || !data.title) {
return; 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) //console.log(buffer)
instance.command.executeImportDocx({ if (data.content instanceof ArrayBuffer) {
arrayBuffer: buffer, 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') { if (eventData.action == 'creation_leader') {
changeAiArticleTextarea(eventData.data, 'outline') changeAiArticleTextarea(eventData.data, 'outline')
} else if (eventData.action == 'creation_builder') { } else if (eventData.action == 'creation_builder') {
@ -2188,10 +2213,10 @@ window.onload = function () {
} }
} }
//window.addEventListener('load', () => { //window.addEventListener('load', () => {
window.parent.postMessage({ type: 'initSuccess' }, '*') window.parent.postMessage({ type: 'initSuccess' }, '*')
window.addEventListener('message', eventHandler) window.addEventListener('message', eventHandler)
//}) //})
window.addEventListener('unload', () => { window.addEventListener('unload', () => {
window.removeEventListener('message', eventHandler) window.removeEventListener('message', eventHandler)

Loading…
Cancel
Save