resolve #273 new feature: protect sheet support

new feature: protect sheet support, relate issue #273
formula
HcySunYang 6 years ago committed by xuri
parent 30122d0346
commit 4dbc78ce0a

@ -1208,6 +1208,19 @@ func TestSearchSheet(t *testing.T) {
t.Log(xlsx.SearchSheet("Sheet1", "A")) 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 { func trimSliceSpace(s []string) []string {
for { for {
if len(s) > 0 && s[len(s)-1] == "" { if len(s) > 0 && s[len(s)-1] == "" {

@ -15,6 +15,8 @@ import (
"io" "io"
"log" "log"
"math" "math"
"strconv"
"strings"
"unicode" "unicode"
) )
@ -199,3 +201,29 @@ func namespaceStrictToTransitional(content []byte) []byte {
} }
return content 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))
}

@ -711,6 +711,47 @@ func (f *File) SearchSheet(sheet, value string) []string {
return result 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 // trimSheetName provides a function to trim invaild characters by given worksheet
// name. // name.
func trimSheetName(name string) string { func trimSheetName(name string) string {

Binary file not shown.

@ -377,26 +377,27 @@ type xlsxF struct {
// xlsxSheetProtection collection expresses the sheet protection options to // xlsxSheetProtection collection expresses the sheet protection options to
// enforce when the sheet is protected. // enforce when the sheet is protected.
type xlsxSheetProtection struct { type xlsxSheetProtection struct {
AlgorithmName string `xml:"algorithmName,attr,omitempty"` AlgorithmName string `xml:"algorithmName,attr,omitempty"`
AutoFilter int `xml:"autoFilter,attr,omitempty"` AutoFilter bool `xml:"autoFilter,attr,omitempty"`
DeleteColumns int `xml:"deleteColumns,attr,omitempty"` DeleteColumns bool `xml:"deleteColumns,attr,omitempty"`
DeleteRows int `xml:"deleteRows,attr,omitempty"` DeleteRows bool `xml:"deleteRows,attr,omitempty"`
FormatCells int `xml:"formatCells,attr,omitempty"` FormatCells bool `xml:"formatCells,attr,omitempty"`
FormatColumns int `xml:"formatColumns,attr,omitempty"` FormatColumns bool `xml:"formatColumns,attr,omitempty"`
FormatRows int `xml:"formatRows,attr,omitempty"` FormatRows bool `xml:"formatRows,attr,omitempty"`
HashValue string `xml:"hashValue,attr,omitempty"` HashValue string `xml:"hashValue,attr,omitempty"`
InsertColumns int `xml:"insertColumns,attr,omitempty"` InsertColumns bool `xml:"insertColumns,attr,omitempty"`
InsertHyperlinks int `xml:"insertHyperlinks,attr,omitempty"` InsertHyperlinks bool `xml:"insertHyperlinks,attr,omitempty"`
InsertRows int `xml:"insertRows,attr,omitempty"` InsertRows bool `xml:"insertRows,attr,omitempty"`
Objects int `xml:"objects,attr,omitempty"` Objects bool `xml:"objects,attr,omitempty"`
PivotTables int `xml:"pivotTables,attr,omitempty"` Password string `xml:"password,attr,omitempty"`
SaltValue string `xml:"saltValue,attr,omitempty"` PivotTables bool `xml:"pivotTables,attr,omitempty"`
Scenarios int `xml:"scenarios,attr,omitempty"` SaltValue string `xml:"saltValue,attr,omitempty"`
SelectLockedCells int `xml:"selectLockedCells,attr,omitempty"` Scenarios bool `xml:"scenarios,attr,omitempty"`
SelectUnlockedCell int `xml:"selectUnlockedCell,attr,omitempty"` SelectLockedCells bool `xml:"selectLockedCells,attr,omitempty"`
Sheet int `xml:"sheet,attr,omitempty"` SelectUnlockedCells bool `xml:"selectUnlockedCells,attr,omitempty"`
Sort int `xml:"sort,attr,omitempty"` Sheet bool `xml:"sheet,attr,omitempty"`
SpinCount int `xml:"spinCount,attr,omitempty"` Sort bool `xml:"sort,attr,omitempty"`
SpinCount int `xml:"spinCount,attr,omitempty"`
} }
// xlsxPhoneticPr (Phonetic Properties) represents a collection of phonetic // xlsxPhoneticPr (Phonetic Properties) represents a collection of phonetic
@ -599,3 +600,23 @@ type formatConditional struct {
MultiRange string `json:"multi_range,omitempty"` MultiRange string `json:"multi_range,omitempty"`
BarColor string `json:"bar_color,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…
Cancel
Save