forked from p30928647/excelize
resolve #273 new feature: protect sheet support
new feature: protect sheet support, relate issue #273
This commit is contained in:
parent
30122d0346
commit
4dbc78ce0a
|
@ -1208,6 +1208,19 @@ func TestSearchSheet(t *testing.T) {
|
|||
t.Log(xlsx.SearchSheet("Sheet1", "A"))
|
||||
}
|
||||
|
||||
func TestProtectSheet(t *testing.T) {
|
||||
xlsx := NewFile()
|
||||
xlsx.ProtectSheet("Sheet1", nil)
|
||||
xlsx.ProtectSheet("Sheet1", &FormatSheetProtection{
|
||||
Password: "password",
|
||||
EditScenarios: false,
|
||||
})
|
||||
err := xlsx.SaveAs("./test/Book_protect_sheet.xlsx")
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func trimSliceSpace(s []string) []string {
|
||||
for {
|
||||
if len(s) > 0 && s[len(s)-1] == "" {
|
||||
|
|
28
lib.go
28
lib.go
|
@ -15,6 +15,8 @@ import (
|
|||
"io"
|
||||
"log"
|
||||
"math"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
|
@ -199,3 +201,29 @@ func namespaceStrictToTransitional(content []byte) []byte {
|
|||
}
|
||||
return content
|
||||
}
|
||||
|
||||
// genSheetPasswd provides a method to generate password for worksheet
|
||||
// protection by given plaintext. When an Excel sheet is being protected with
|
||||
// a password, a 16-bit (two byte) long hash is generated. To verify a
|
||||
// password, it is compared to the hash. Obviously, if the input data volume
|
||||
// is great, numerous passwords will match the same hash. Here is the
|
||||
// algorithm to create the hash value:
|
||||
//
|
||||
// take the ASCII values of all characters shift left the first character 1 bit, the second 2 bits and so on (use only the lower 15 bits and rotate all higher bits, the highest bit of the 16-bit value is always 0 [signed short])
|
||||
// XOR all these values
|
||||
// XOR the count of characters
|
||||
// XOR the constant 0xCE4B
|
||||
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))
|
||||
}
|
||||
|
|
41
sheet.go
41
sheet.go
|
@ -711,6 +711,47 @@ func (f *File) SearchSheet(sheet, value string) []string {
|
|||
return result
|
||||
}
|
||||
|
||||
// ProtectSheet provides a function to prevent other users from accidentally
|
||||
// or deliberately changing, moving, or deleting data in a worksheet. For
|
||||
// example protect Sheet1 with protection settings:
|
||||
//
|
||||
// xlsx.ProtectSheet("Sheet1", &excelize.FormatSheetProtection{
|
||||
// Password: "password",
|
||||
// EditScenarios: false,
|
||||
// })
|
||||
//
|
||||
func (f *File) ProtectSheet(sheet string, settings *FormatSheetProtection) {
|
||||
xlsx := f.workSheetReader(sheet)
|
||||
if settings == nil {
|
||||
settings = &FormatSheetProtection{
|
||||
EditObjects: true,
|
||||
EditScenarios: true,
|
||||
SelectLockedCells: true,
|
||||
}
|
||||
}
|
||||
xlsx.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 != "" {
|
||||
xlsx.SheetProtection.Password = genSheetPasswd(settings.Password)
|
||||
}
|
||||
}
|
||||
|
||||
// trimSheetName provides a function to trim invaild characters by given worksheet
|
||||
// name.
|
||||
func trimSheetName(name string) string {
|
||||
|
|
Binary file not shown.
|
@ -377,26 +377,27 @@ type xlsxF struct {
|
|||
// xlsxSheetProtection collection expresses the sheet protection options to
|
||||
// enforce when the sheet is protected.
|
||||
type xlsxSheetProtection struct {
|
||||
AlgorithmName string `xml:"algorithmName,attr,omitempty"`
|
||||
AutoFilter int `xml:"autoFilter,attr,omitempty"`
|
||||
DeleteColumns int `xml:"deleteColumns,attr,omitempty"`
|
||||
DeleteRows int `xml:"deleteRows,attr,omitempty"`
|
||||
FormatCells int `xml:"formatCells,attr,omitempty"`
|
||||
FormatColumns int `xml:"formatColumns,attr,omitempty"`
|
||||
FormatRows int `xml:"formatRows,attr,omitempty"`
|
||||
HashValue string `xml:"hashValue,attr,omitempty"`
|
||||
InsertColumns int `xml:"insertColumns,attr,omitempty"`
|
||||
InsertHyperlinks int `xml:"insertHyperlinks,attr,omitempty"`
|
||||
InsertRows int `xml:"insertRows,attr,omitempty"`
|
||||
Objects int `xml:"objects,attr,omitempty"`
|
||||
PivotTables int `xml:"pivotTables,attr,omitempty"`
|
||||
SaltValue string `xml:"saltValue,attr,omitempty"`
|
||||
Scenarios int `xml:"scenarios,attr,omitempty"`
|
||||
SelectLockedCells int `xml:"selectLockedCells,attr,omitempty"`
|
||||
SelectUnlockedCell int `xml:"selectUnlockedCell,attr,omitempty"`
|
||||
Sheet int `xml:"sheet,attr,omitempty"`
|
||||
Sort int `xml:"sort,attr,omitempty"`
|
||||
SpinCount int `xml:"spinCount,attr,omitempty"`
|
||||
AlgorithmName string `xml:"algorithmName,attr,omitempty"`
|
||||
AutoFilter bool `xml:"autoFilter,attr,omitempty"`
|
||||
DeleteColumns bool `xml:"deleteColumns,attr,omitempty"`
|
||||
DeleteRows bool `xml:"deleteRows,attr,omitempty"`
|
||||
FormatCells bool `xml:"formatCells,attr,omitempty"`
|
||||
FormatColumns bool `xml:"formatColumns,attr,omitempty"`
|
||||
FormatRows bool `xml:"formatRows,attr,omitempty"`
|
||||
HashValue string `xml:"hashValue,attr,omitempty"`
|
||||
InsertColumns bool `xml:"insertColumns,attr,omitempty"`
|
||||
InsertHyperlinks bool `xml:"insertHyperlinks,attr,omitempty"`
|
||||
InsertRows bool `xml:"insertRows,attr,omitempty"`
|
||||
Objects bool `xml:"objects,attr,omitempty"`
|
||||
Password string `xml:"password,attr,omitempty"`
|
||||
PivotTables bool `xml:"pivotTables,attr,omitempty"`
|
||||
SaltValue string `xml:"saltValue,attr,omitempty"`
|
||||
Scenarios bool `xml:"scenarios,attr,omitempty"`
|
||||
SelectLockedCells bool `xml:"selectLockedCells,attr,omitempty"`
|
||||
SelectUnlockedCells bool `xml:"selectUnlockedCells,attr,omitempty"`
|
||||
Sheet bool `xml:"sheet,attr,omitempty"`
|
||||
Sort bool `xml:"sort,attr,omitempty"`
|
||||
SpinCount int `xml:"spinCount,attr,omitempty"`
|
||||
}
|
||||
|
||||
// xlsxPhoneticPr (Phonetic Properties) represents a collection of phonetic
|
||||
|
@ -599,3 +600,23 @@ type formatConditional struct {
|
|||
MultiRange string `json:"multi_range,omitempty"`
|
||||
BarColor string `json:"bar_color,omitempty"`
|
||||
}
|
||||
|
||||
// FormatSheetProtection directly maps the settings of worksheet protection.
|
||||
type FormatSheetProtection struct {
|
||||
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
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue