protection.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. # Copyright (c) 2010-2024 openpyxl
  2. from openpyxl.descriptors.serialisable import Serialisable
  3. from openpyxl.descriptors import (
  4. Alias,
  5. Typed,
  6. String,
  7. Float,
  8. Integer,
  9. Bool,
  10. NoneSet,
  11. Set,
  12. )
  13. from openpyxl.descriptors.excel import (
  14. ExtensionList,
  15. HexBinary,
  16. Guid,
  17. Relation,
  18. Base64Binary,
  19. )
  20. from openpyxl.utils.protection import hash_password
  21. class WorkbookProtection(Serialisable):
  22. _workbook_password, _revisions_password = None, None
  23. tagname = "workbookPr"
  24. workbook_password = Alias("workbookPassword")
  25. workbookPasswordCharacterSet = String(allow_none=True)
  26. revision_password = Alias("revisionsPassword")
  27. revisionsPasswordCharacterSet = String(allow_none=True)
  28. lockStructure = Bool(allow_none=True)
  29. lock_structure = Alias("lockStructure")
  30. lockWindows = Bool(allow_none=True)
  31. lock_windows = Alias("lockWindows")
  32. lockRevision = Bool(allow_none=True)
  33. lock_revision = Alias("lockRevision")
  34. revisionsAlgorithmName = String(allow_none=True)
  35. revisionsHashValue = Base64Binary(allow_none=True)
  36. revisionsSaltValue = Base64Binary(allow_none=True)
  37. revisionsSpinCount = Integer(allow_none=True)
  38. workbookAlgorithmName = String(allow_none=True)
  39. workbookHashValue = Base64Binary(allow_none=True)
  40. workbookSaltValue = Base64Binary(allow_none=True)
  41. workbookSpinCount = Integer(allow_none=True)
  42. __attrs__ = ('workbookPassword', 'workbookPasswordCharacterSet', 'revisionsPassword',
  43. 'revisionsPasswordCharacterSet', 'lockStructure', 'lockWindows', 'lockRevision',
  44. 'revisionsAlgorithmName', 'revisionsHashValue', 'revisionsSaltValue',
  45. 'revisionsSpinCount', 'workbookAlgorithmName', 'workbookHashValue',
  46. 'workbookSaltValue', 'workbookSpinCount')
  47. def __init__(self,
  48. workbookPassword=None,
  49. workbookPasswordCharacterSet=None,
  50. revisionsPassword=None,
  51. revisionsPasswordCharacterSet=None,
  52. lockStructure=None,
  53. lockWindows=None,
  54. lockRevision=None,
  55. revisionsAlgorithmName=None,
  56. revisionsHashValue=None,
  57. revisionsSaltValue=None,
  58. revisionsSpinCount=None,
  59. workbookAlgorithmName=None,
  60. workbookHashValue=None,
  61. workbookSaltValue=None,
  62. workbookSpinCount=None,
  63. ):
  64. if workbookPassword is not None:
  65. self.workbookPassword = workbookPassword
  66. self.workbookPasswordCharacterSet = workbookPasswordCharacterSet
  67. if revisionsPassword is not None:
  68. self.revisionsPassword = revisionsPassword
  69. self.revisionsPasswordCharacterSet = revisionsPasswordCharacterSet
  70. self.lockStructure = lockStructure
  71. self.lockWindows = lockWindows
  72. self.lockRevision = lockRevision
  73. self.revisionsAlgorithmName = revisionsAlgorithmName
  74. self.revisionsHashValue = revisionsHashValue
  75. self.revisionsSaltValue = revisionsSaltValue
  76. self.revisionsSpinCount = revisionsSpinCount
  77. self.workbookAlgorithmName = workbookAlgorithmName
  78. self.workbookHashValue = workbookHashValue
  79. self.workbookSaltValue = workbookSaltValue
  80. self.workbookSpinCount = workbookSpinCount
  81. def set_workbook_password(self, value='', already_hashed=False):
  82. """Set a password on this workbook."""
  83. if not already_hashed:
  84. value = hash_password(value)
  85. self._workbook_password = value
  86. @property
  87. def workbookPassword(self):
  88. """Return the workbook password value, regardless of hash."""
  89. return self._workbook_password
  90. @workbookPassword.setter
  91. def workbookPassword(self, value):
  92. """Set a workbook password directly, forcing a hash step."""
  93. self.set_workbook_password(value)
  94. def set_revisions_password(self, value='', already_hashed=False):
  95. """Set a revision password on this workbook."""
  96. if not already_hashed:
  97. value = hash_password(value)
  98. self._revisions_password = value
  99. @property
  100. def revisionsPassword(self):
  101. """Return the revisions password value, regardless of hash."""
  102. return self._revisions_password
  103. @revisionsPassword.setter
  104. def revisionsPassword(self, value):
  105. """Set a revisions password directly, forcing a hash step."""
  106. self.set_revisions_password(value)
  107. @classmethod
  108. def from_tree(cls, node):
  109. """Don't hash passwords when deserialising from XML"""
  110. self = super().from_tree(node)
  111. if self.workbookPassword:
  112. self.set_workbook_password(node.get('workbookPassword'), already_hashed=True)
  113. if self.revisionsPassword:
  114. self.set_revisions_password(node.get('revisionsPassword'), already_hashed=True)
  115. return self
  116. # Backwards compatibility
  117. DocumentSecurity = WorkbookProtection
  118. class FileSharing(Serialisable):
  119. tagname = "fileSharing"
  120. readOnlyRecommended = Bool(allow_none=True)
  121. userName = String(allow_none=True)
  122. reservationPassword = HexBinary(allow_none=True)
  123. algorithmName = String(allow_none=True)
  124. hashValue = Base64Binary(allow_none=True)
  125. saltValue = Base64Binary(allow_none=True)
  126. spinCount = Integer(allow_none=True)
  127. def __init__(self,
  128. readOnlyRecommended=None,
  129. userName=None,
  130. reservationPassword=None,
  131. algorithmName=None,
  132. hashValue=None,
  133. saltValue=None,
  134. spinCount=None,
  135. ):
  136. self.readOnlyRecommended = readOnlyRecommended
  137. self.userName = userName
  138. self.reservationPassword = reservationPassword
  139. self.algorithmName = algorithmName
  140. self.hashValue = hashValue
  141. self.saltValue = saltValue
  142. self.spinCount = spinCount