Go-Excelize API源码阅读(三十一)—— ProtectSheet(sheet string, settings *SheetProtectionoptions)
开源摘星计划(WeOpen Star) 是由腾源会 2022 年推出的全新项目,旨在为开源人提供成长激励,为开源项目提供成长支持,助力开发者更好地了解开源,更快地跨越鸿沟,参与到开源的具体贡献与实践中。
不管你是开源萌新,还是希望更深度参与开源贡献的老兵,跟随“开源摘星计划”开启你的开源之旅,从一篇学习笔记、到一段代码的提交,不断挖掘自己的潜能,最终成长为开源社区的“闪亮之星”。
我们将同你一起,探索更多的可能性!
项目地址: WeOpen-Star:https://github.com/weopenprojects/WeOpen-Star
一、Go-Excelize简介
Excelize 是 Go 语言编写的用于操作 Office Excel 文档基础库,基于 ECMA-376,ISO/IEC 29500 国际标准。可以使用它来读取、写入由 Microsoft Excel™ 2007 及以上版本创建的电子表格文档。支持 XLAM / XLSM / XLSX / XLTM / XLTX 等多种文档格式,高度兼容带有样式、图片(表)、透视表、切片器等复杂组件的文档,并提供流式读写 API,用于处理包含大规模数据的工作簿。可应用于各类报表平台、云计算、边缘计算等系统。使用本类库要求使用的 Go 语言为 1.15 或更高版本。
二、ProtectSheet(sheet string, settings *SheetProtectionoptions)
func (f *File) ProtectSheet(sheet string, settings *SheetProtectionoptions) error
防止其他用户意外或有意更改、移动或删除工作表中的数据。可选字段 AlgorithmName 支持指定哈希算法 XOR、MD4、MD5、SHA-1、SHA-256、SHA-384 或 SHA-512,如果未指定哈希算法,默认使用 XOR 算法。例如,将名为 Sheet1 的工作表设置密码保护,但是允许选择锁定的单元格、选择未锁定的单元格、编辑方案:
err := f.ProtectSheet("Sheet1", &excelize.SheetProtectionoptions{
AlgorithmName: "SHA-512",
Password: "password",
EditScenarios: false,
})
SheetProtectionoptions 定义了保护工作表的设置选项。
type SheetProtectionoptions struct {
AlgorithmName string
AutoFilter bool
DeleteColumns bool
DeleteRows bool
EditObjects bool
EditScenarios bool
FormatCells bool
FormatColumns bool
FormatRows bool
InsertColumns bool
InsertHyperlinks bool
InsertRows bool
Password string
Pivottables bool
SelectLockedCells bool
SelectUnlockedCells bool
Sort bool
}
我们直接来看一看源码:
func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) error {
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
if settings == nil {
settings = &FormatSheetProtection{
EditObjects: true,
EditScenarios: true,
SelectLockedCells: true,
}
}
ws.SheetProtection = &xlsxSheetProtection{
AutoFilter: settings.AutoFilter,
DeleteColumns: settings.DeleteColumns,
DeleteRows: settings.DeleteRows,
FormatCells: settings.FormatCells,
FormatColumns: settings.FormatColumns,
FormatRows: settings.FormatRows,
InsertColumns: settings.InsertColumns,
InsertHyperlinks: settings.InsertHyperlinks,
InsertRows: settings.InsertRows,
Objects: settings.EditObjects,
Pivottables: settings.Pivottables,
Scenarios: settings.EditScenarios,
SelectLockedCells: settings.SelectLockedCells,
SelectUnlockedCells: settings.SelectUnlockedCells,
Sheet: true,
Sort: settings.sort,
}
if settings.Password != "" {
if settings.AlgorithmName == "" {
ws.SheetProtection.Password = genSheetPasswd(settings.Password)
return err
}
hashValue, saltValue, err := genISOPasswdHash(settings.Password, settings.AlgorithmName, "", int(sheetProtectionSpinCount))
if err != nil {
return err
}
ws.SheetProtection.Password = ""
ws.SheetProtection.AlgorithmName = settings.AlgorithmName
ws.SheetProtection.SaltValue = saltValue
ws.SheetProtection.HashValue = hashValue
ws.SheetProtection.SpinCount = int(sheetProtectionSpinCount)
}
return err
}
整个逻辑比较简单:
ws, err := f.workSheetReader(sheet)
if err != nil {
return err
}
先读取工作表。
if settings == nil {
settings = &FormatSheetProtection{
EditObjects: true,
EditScenarios: true,
SelectLockedCells: true,
}
}
ws.SheetProtection = &xlsxSheetProtection{
AutoFilter: settings.AutoFilter,
DeleteColumns: settings.DeleteColumns,
DeleteRows: settings.DeleteRows,
FormatCells: settings.FormatCells,
FormatColumns: settings.FormatColumns,
FormatRows: settings.FormatRows,
InsertColumns: settings.InsertColumns,
InsertHyperlinks: settings.InsertHyperlinks,
InsertRows: settings.InsertRows,
Objects: settings.EditObjects,
Pivottables: settings.Pivottables,
Scenarios: settings.EditScenarios,
SelectLockedCells: settings.SelectLockedCells,
SelectUnlockedCells: settings.SelectUnlockedCells,
Sheet: true,
Sort: settings.sort,
}
如果参数settings为空,我们就新建一个 FormatSheetProtection结构体,给EditObjects、EditScenarios、SelectLockedCells这三个参数分配为true。
ws.SheetProtection = &xlsxSheetProtection{
AutoFilter: settings.AutoFilter,
DeleteColumns: settings.DeleteColumns,
DeleteRows: settings.DeleteRows,
FormatCells: settings.FormatCells,
FormatColumns: settings.FormatColumns,
FormatRows: settings.FormatRows,
InsertColumns: settings.InsertColumns,
InsertHyperlinks: settings.InsertHyperlinks,
InsertRows: settings.InsertRows,
Objects: settings.EditObjects,
Pivottables: settings.Pivottables,
Scenarios: settings.EditScenarios,
SelectLockedCells: settings.SelectLockedCells,
SelectUnlockedCells: settings.SelectUnlockedCells,
Sheet: true,
Sort: settings.sort,
}
然后再新建一个xlsxSheetProtection结构体,用settings内的成员给其赋值。
if settings.Password != "" {
if settings.AlgorithmName == "" {
ws.SheetProtection.Password = genSheetPasswd(settings.Password)
return err
}
hashValue, saltValue, err := genISOPasswdHash(settings.Password, settings.AlgorithmName, "", int(sheetProtectionSpinCount))
if err != nil {
return err
}
ws.SheetProtection.Password = ""
ws.SheetProtection.AlgorithmName = settings.AlgorithmName
ws.SheetProtection.SaltValue = saltValue
ws.SheetProtection.HashValue = hashValue
ws.SheetProtection.SpinCount = int(sheetProtectionSpinCount)
}
return err
然后再看最后一部分,如果settings的Password不为空,就进入这部分逻辑。 先判断settings.AlgorithmName是否为空,如果为空,就调用genSheetPasswd函数,将Password字段转换成另一种密码形式:
func genSheetPasswd(plaintext string) string {
var password int64 = 0x0000
var charPos uint = 1
for _, v := range plaintext {
value := int64(v) << charPos
charPos++
rotatedBits := value >> 15 // rotated bits beyond bit 15
value &= 0x7fff // first 15 bits
password ^= value | rotatedBits
}
password ^= int64(len(plaintext))
password ^= 0xCE4B
return strings.toupper(strconv.FormatInt(password, 16))
}
hashValue, saltValue, err := genISOPasswdHash(settings.Password, settings.AlgorithmName, "", int(sheetProtectionSpinCount))
if err != nil {
return err
}
然后使用genISOPasswdHash,通过给定的明文密码、加密散列算法的名称、盐值和自旋次数来实现ISO密码散列算法。
ws.SheetProtection.Password = ""
ws.SheetProtection.AlgorithmName = settings.AlgorithmName
ws.SheetProtection.SaltValue = saltValue
ws.SheetProtection.HashValue = hashValue
ws.SheetProtection.SpinCount = int(sheetProtectionSpinCount)
最后将生成的hash值、盐值、哈希算法名、自旋次数等放入结构体。
原文地址:https://cloud.tencent.com/developer/article/2169998
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。