mirror of
https://github.com/unidoc/unipdf.git
synced 2025-04-30 13:48:51 +08:00
core: change permissions type to a bitmask
This commit is contained in:
parent
ef64bef191
commit
b5288e7ddc
@ -37,7 +37,7 @@ type PdfCrypt struct {
|
|||||||
U []byte
|
U []byte
|
||||||
OE []byte // R=6
|
OE []byte // R=6
|
||||||
UE []byte // R=6
|
UE []byte // R=6
|
||||||
P uint32
|
P AccessPermissions
|
||||||
Perms []byte // R=6
|
Perms []byte // R=6
|
||||||
EncryptMetadata bool
|
EncryptMetadata bool
|
||||||
Id0 string
|
Id0 string
|
||||||
@ -56,22 +56,29 @@ type PdfCrypt struct {
|
|||||||
ivAESZero []byte // a zero buffer used as an initialization vector for AES
|
ivAESZero []byte // a zero buffer used as an initialization vector for AES
|
||||||
}
|
}
|
||||||
|
|
||||||
// AccessPermissions is a list of access permissions for a PDF file.
|
// AccessPermissions is a bitmask of access permissions for a PDF file.
|
||||||
type AccessPermissions struct {
|
type AccessPermissions uint32
|
||||||
Printing bool
|
|
||||||
Modify bool
|
|
||||||
ExtractGraphics bool
|
|
||||||
Annotate bool
|
|
||||||
|
|
||||||
// Allow form filling, if annotation is disabled? If annotation enabled, is not looked at.
|
const (
|
||||||
FillForms bool
|
// PermOwner grants all permissions.
|
||||||
DisabilityExtract bool // not clear what this means!
|
PermOwner = AccessPermissions(math.MaxUint32)
|
||||||
|
|
||||||
// Allow rotating, editing page order.
|
PermPrinting = AccessPermissions(1 << 2) // bit 3
|
||||||
RotateInsert bool
|
PermModify = AccessPermissions(1 << 3) // bit 4
|
||||||
|
PermExtractGraphics = AccessPermissions(1 << 4) // bit 5
|
||||||
|
PermAnnotate = AccessPermissions(1 << 5) // bit 6
|
||||||
|
// PermFillForms allow form filling, if annotation is disabled? If annotation enabled, is not looked at.
|
||||||
|
PermFillForms = AccessPermissions(1 << 8) // bit 9
|
||||||
|
PermDisabilityExtract = AccessPermissions(1 << 9) // bit 10 // TODO: not clear what this means!
|
||||||
|
// PermRotateInsert allows rotating, editing page order.
|
||||||
|
PermRotateInsert = AccessPermissions(1 << 10) // bit 11
|
||||||
|
// PermFullPrintQuality limits print quality (lowres), assuming Printing bit is set.
|
||||||
|
PermFullPrintQuality = AccessPermissions(1 << 11) // bit 12
|
||||||
|
)
|
||||||
|
|
||||||
// Limit print quality (lowres), assuming Printing is true.
|
// Allowed checks if a set of permissions can be granted.
|
||||||
FullPrintQuality bool
|
func (p AccessPermissions) Allowed(p2 AccessPermissions) bool {
|
||||||
|
return p&p2 == p2
|
||||||
}
|
}
|
||||||
|
|
||||||
const padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF" +
|
const padding = "\x28\xBF\x4E\x5E\x4E\x75\x8A\x41\x64\x00\x4E\x56\xFF" +
|
||||||
@ -424,7 +431,7 @@ func PdfCryptMakeNew(parser *PdfParser, ed, trailer *PdfObjectDictionary) (PdfCr
|
|||||||
if !ok {
|
if !ok {
|
||||||
return crypter, errors.New("Encrypt dictionary missing permissions attr")
|
return crypter, errors.New("Encrypt dictionary missing permissions attr")
|
||||||
}
|
}
|
||||||
crypter.P = uint32(*P)
|
crypter.P = AccessPermissions(*P)
|
||||||
|
|
||||||
if crypter.R == 6 {
|
if crypter.R == 6 {
|
||||||
Perms, ok := ed.Get("Perms").(*PdfObjectString)
|
Perms, ok := ed.Get("Perms").(*PdfObjectString)
|
||||||
@ -464,65 +471,7 @@ func PdfCryptMakeNew(parser *PdfParser, ed, trailer *PdfObjectDictionary) (PdfCr
|
|||||||
|
|
||||||
// GetAccessPermissions returns the PDF access permissions as an AccessPermissions object.
|
// GetAccessPermissions returns the PDF access permissions as an AccessPermissions object.
|
||||||
func (crypt *PdfCrypt) GetAccessPermissions() AccessPermissions {
|
func (crypt *PdfCrypt) GetAccessPermissions() AccessPermissions {
|
||||||
perms := AccessPermissions{}
|
return crypt.P
|
||||||
|
|
||||||
P := crypt.P
|
|
||||||
if P&(1<<2) > 0 {
|
|
||||||
perms.Printing = true
|
|
||||||
}
|
|
||||||
if P&(1<<3) > 0 {
|
|
||||||
perms.Modify = true
|
|
||||||
}
|
|
||||||
if P&(1<<4) > 0 {
|
|
||||||
perms.ExtractGraphics = true
|
|
||||||
}
|
|
||||||
if P&(1<<5) > 0 {
|
|
||||||
perms.Annotate = true
|
|
||||||
}
|
|
||||||
if P&(1<<8) > 0 {
|
|
||||||
perms.FillForms = true
|
|
||||||
}
|
|
||||||
if P&(1<<9) > 0 {
|
|
||||||
perms.DisabilityExtract = true
|
|
||||||
}
|
|
||||||
if P&(1<<10) > 0 {
|
|
||||||
perms.RotateInsert = true
|
|
||||||
}
|
|
||||||
if P&(1<<11) > 0 {
|
|
||||||
perms.FullPrintQuality = true
|
|
||||||
}
|
|
||||||
return perms
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetP returns the P entry to be used in Encrypt dictionary based on AccessPermissions settings.
|
|
||||||
func (perms AccessPermissions) GetP() uint32 {
|
|
||||||
var P uint32
|
|
||||||
|
|
||||||
if perms.Printing { // bit 3
|
|
||||||
P |= (1 << 2)
|
|
||||||
}
|
|
||||||
if perms.Modify { // bit 4
|
|
||||||
P |= (1 << 3)
|
|
||||||
}
|
|
||||||
if perms.ExtractGraphics { // bit 5
|
|
||||||
P |= (1 << 4)
|
|
||||||
}
|
|
||||||
if perms.Annotate { // bit 6
|
|
||||||
P |= (1 << 5)
|
|
||||||
}
|
|
||||||
if perms.FillForms {
|
|
||||||
P |= (1 << 8) // bit 9
|
|
||||||
}
|
|
||||||
if perms.DisabilityExtract {
|
|
||||||
P |= (1 << 9) // bit 10
|
|
||||||
}
|
|
||||||
if perms.RotateInsert {
|
|
||||||
P |= (1 << 10) // bit 11
|
|
||||||
}
|
|
||||||
if perms.FullPrintQuality {
|
|
||||||
P |= (1 << 11) // bit 12
|
|
||||||
}
|
|
||||||
return P
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether the specified password can be used to decrypt the document.
|
// Check whether the specified password can be used to decrypt the document.
|
||||||
@ -575,8 +524,6 @@ func (crypt *PdfCrypt) authenticate(password []byte) (bool, error) {
|
|||||||
// The AccessPermissions shows what access the user has for editing etc.
|
// The AccessPermissions shows what access the user has for editing etc.
|
||||||
// An error is returned if there was a problem performing the authentication.
|
// An error is returned if there was a problem performing the authentication.
|
||||||
func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, AccessPermissions, error) {
|
func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, AccessPermissions, error) {
|
||||||
perms := AccessPermissions{}
|
|
||||||
|
|
||||||
// Try owner password -> full rights.
|
// Try owner password -> full rights.
|
||||||
var (
|
var (
|
||||||
isOwner bool
|
isOwner bool
|
||||||
@ -586,26 +533,18 @@ func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, AccessPermissio
|
|||||||
var h []byte
|
var h []byte
|
||||||
h, err = crypt.alg12(password)
|
h, err = crypt.alg12(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, perms, err
|
return false, 0, err
|
||||||
}
|
}
|
||||||
isOwner = len(h) != 0
|
isOwner = len(h) != 0
|
||||||
} else {
|
} else {
|
||||||
isOwner, err = crypt.alg7(password)
|
isOwner, err = crypt.alg7(password)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, perms, err
|
return false, 0, err
|
||||||
}
|
}
|
||||||
if isOwner {
|
if isOwner {
|
||||||
// owner -> full rights.
|
// owner -> full rights.
|
||||||
perms.Annotate = true
|
return true, PermOwner, nil
|
||||||
perms.DisabilityExtract = true
|
|
||||||
perms.ExtractGraphics = true
|
|
||||||
perms.FillForms = true
|
|
||||||
perms.FullPrintQuality = true
|
|
||||||
perms.Modify = true
|
|
||||||
perms.Printing = true
|
|
||||||
perms.RotateInsert = true
|
|
||||||
return true, perms, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try user password.
|
// Try user password.
|
||||||
@ -614,22 +553,22 @@ func (crypt *PdfCrypt) checkAccessRights(password []byte) (bool, AccessPermissio
|
|||||||
var h []byte
|
var h []byte
|
||||||
h, err = crypt.alg11(password)
|
h, err = crypt.alg11(password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, perms, err
|
return false, 0, err
|
||||||
}
|
}
|
||||||
isUser = len(h) != 0
|
isUser = len(h) != 0
|
||||||
} else {
|
} else {
|
||||||
isUser, err = crypt.alg6(password)
|
isUser, err = crypt.alg6(password)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, perms, err
|
return false, 0, err
|
||||||
}
|
}
|
||||||
if isUser {
|
if isUser {
|
||||||
// User password specified correctly -> access granted with specified permissions.
|
// User password specified correctly -> access granted with specified permissions.
|
||||||
return true, crypt.GetAccessPermissions(), nil
|
return true, crypt.P, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cannot even view the file.
|
// Cannot even view the file.
|
||||||
return false, perms, nil
|
return false, 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (crypt *PdfCrypt) paddedPass(pass []byte) []byte {
|
func (crypt *PdfCrypt) paddedPass(pass []byte) []byte {
|
||||||
@ -1752,7 +1691,7 @@ func (crypt *PdfCrypt) alg13(fkey []byte) (bool, error) {
|
|||||||
if !bytes.Equal(perms[9:12], []byte("adb")) {
|
if !bytes.Equal(perms[9:12], []byte("adb")) {
|
||||||
return false, errors.New("decoded permissions are invalid")
|
return false, errors.New("decoded permissions are invalid")
|
||||||
}
|
}
|
||||||
p := binary.LittleEndian.Uint32(perms[0:4])
|
p := AccessPermissions(binary.LittleEndian.Uint32(perms[0:4]))
|
||||||
if p != crypt.P {
|
if p != crypt.P {
|
||||||
return false, errors.New("permissions validation failed")
|
return false, errors.New("permissions validation failed")
|
||||||
}
|
}
|
||||||
|
@ -1644,17 +1644,7 @@ func (parser *PdfParser) CheckAccessRights(password []byte) (bool, AccessPermiss
|
|||||||
// Also build the encryption/decryption key.
|
// Also build the encryption/decryption key.
|
||||||
if parser.crypter == nil {
|
if parser.crypter == nil {
|
||||||
// If the crypter is not set, the file is not encrypted and we can assume full access permissions.
|
// If the crypter is not set, the file is not encrypted and we can assume full access permissions.
|
||||||
perms := AccessPermissions{}
|
return true, PermOwner, nil
|
||||||
perms.Printing = true
|
|
||||||
perms.Modify = true
|
|
||||||
perms.FillForms = true
|
|
||||||
perms.RotateInsert = true
|
|
||||||
perms.ExtractGraphics = true
|
|
||||||
perms.DisabilityExtract = true
|
|
||||||
perms.Annotate = true
|
|
||||||
perms.FullPrintQuality = true
|
|
||||||
return true, perms, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return parser.crypter.checkAccessRights(password)
|
return parser.crypter.checkAccessRights(password)
|
||||||
}
|
}
|
||||||
|
@ -716,7 +716,7 @@ func (this *PdfWriter) Encrypt(userPass, ownerPass []byte, options *EncryptOptio
|
|||||||
crypter.P = math.MaxUint32
|
crypter.P = math.MaxUint32
|
||||||
crypter.EncryptMetadata = true
|
crypter.EncryptMetadata = true
|
||||||
if options != nil {
|
if options != nil {
|
||||||
crypter.P = options.Permissions.GetP()
|
crypter.P = options.Permissions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the encryption dictionary.
|
// Generate the encryption dictionary.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user