glasswall.libraries.editor.editor
1import ctypes as ct 2import functools 3import io 4import os 5from contextlib import contextmanager 6from typing import Optional, Union 7 8import glasswall 9from glasswall import determine_file_type as dft 10from glasswall import utils 11from glasswall.config.logging import format_object, log 12from glasswall.libraries.editor import errors, successes 13from glasswall.libraries.library import Library 14 15 16class Editor(Library): 17 """ A high level Python wrapper for Glasswall Editor / Core2. """ 18 19 def __init__(self, library_path: str, licence: Union[str, bytes, bytearray, io.BytesIO] = None): 20 """ Initialise the Editor instance. 21 22 Args: 23 library_path (str): The file or directory path to the Editor library. 24 licence (str, bytes, bytearray, or io.BytesIO, optional): The licence file content or path. This can be: 25 - A string representing the file path to the licence. 26 - A `bytes` or `bytearray` object containing the licence data. 27 - An `io.BytesIO` object for in-memory licence data. 28 If not specified, it is assumed that the licence file is located in the same directory as the `library_path`. 29 """ 30 super().__init__(library_path) 31 self.library = self.load_library(os.path.abspath(library_path)) 32 self.licence = licence 33 34 # Validate killswitch has not activated 35 self.validate_licence() 36 37 log.info(f"Loaded Glasswall {self.__class__.__name__} version {self.version()} from {self.library_path}") 38 39 def validate_licence(self): 40 """ Validates the licence of the library by checking the licence details. 41 42 Raises: 43 LicenceExpired: If the licence has expired or could not be validated. 44 """ 45 licence_details = self.licence_details() 46 47 bad_details = [ 48 "Unable to Read Licence Key File", 49 "Licence File Missing Required Contents", 50 "Licence Expired", 51 ] 52 53 if any(bad_detail.lower() in licence_details.lower() for bad_detail in bad_details): 54 # bad_details found in licence_details 55 log.error(f"{self.__class__.__name__} licence validation failed. Licence details:\n{licence_details}") 56 raise errors.LicenceExpired(licence_details) 57 else: 58 log.debug(f"{self.__class__.__name__} licence validated successfully. Licence details:\n{licence_details}") 59 60 def version(self): 61 """ Returns the Glasswall library version. 62 63 Returns: 64 version (str): The Glasswall library version. 65 """ 66 # API function declaration 67 self.library.GW2LibVersion.restype = ct.c_char_p 68 69 # API call 70 version = self.library.GW2LibVersion() 71 72 # Convert to Python string 73 version = ct.string_at(version).decode() 74 75 return version 76 77 def open_session(self): 78 """ Open a new Glasswall session. 79 80 Returns: 81 session (int): An incrementing integer repsenting the current session. 82 """ 83 # API call 84 session = self.library.GW2OpenSession() 85 86 log.debug(f"\n\tsession: {session}") 87 88 if self.licence: 89 # Must register licence on each GW2OpenSession if the licence is not in the same directory as the library 90 self.register_licence(session, self.licence) 91 92 return session 93 94 def close_session(self, session: int) -> int: 95 """ Close the Glasswall session. All resources allocated by the session will be destroyed. 96 97 Args: 98 session (int): The session to close. 99 100 Returns: 101 status (int): The status code of the function call. 102 """ 103 if not isinstance(session, int): 104 raise TypeError(session) 105 106 # API function declaration 107 self.library.GW2CloseSession.argtypes = [ct.c_size_t] 108 109 # Variable initialisation 110 ct_session = ct.c_size_t(session) 111 112 # API call 113 status = self.library.GW2CloseSession(ct_session) 114 115 if status not in successes.success_codes: 116 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 117 else: 118 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 119 120 return status 121 122 @contextmanager 123 def new_session(self): 124 """ Context manager. Opens a new session on entry and closes the session on exit. """ 125 try: 126 session = self.open_session() 127 yield session 128 finally: 129 self.close_session(session) 130 131 def run_session(self, session): 132 """ Runs the Glasswall session and begins processing of a file. 133 134 Args: 135 session (int): The session to run. 136 137 Returns: 138 status (int): The status code of the function call. 139 """ 140 # API function declaration 141 self.library.GW2RunSession.argtypes = [ct.c_size_t] 142 143 # Variable initialisation 144 ct_session = ct.c_size_t(session) 145 146 # API call 147 status = self.library.GW2RunSession(ct_session) 148 149 if status not in successes.success_codes: 150 log.error(f"\n\tsession: {session}\n\tstatus: {status}\n\tGW2FileErrorMsg: {self.file_error_message(session)}") 151 else: 152 log.debug(f"\n\tsession: {session}\n\tstatus: {status}\n\tGW2FileErrorMsg: {self.file_error_message(session)}") 153 154 return status 155 156 def determine_file_type(self, input_file: Union[str, bytes, bytearray, io.BytesIO], as_string: bool = False, raise_unsupported: bool = True) -> Union[int, str]: 157 """ Determine the file type of a given input file, either as an integer identifier or a string. 158 159 Args: 160 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file to analyse. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. 161 as_string (bool, optional): Return file type as string, eg: "bmp" instead of: 29. Defaults to False. 162 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 163 164 Returns: 165 file_type (Union[int, str]): The file type. 166 """ 167 if isinstance(input_file, str): 168 if not os.path.isfile(input_file): 169 raise FileNotFoundError(input_file) 170 171 # convert to ct.c_char_p of bytes 172 ct_input_file = ct.c_char_p(input_file.encode("utf-8")) 173 174 # API call 175 file_type = self.library.GW2DetermineFileTypeFromFile(ct_input_file) 176 177 elif isinstance(input_file, (bytes, bytearray, io.BytesIO)): 178 # convert to bytes 179 bytes_input_file = utils.as_bytes(input_file) 180 181 # ctypes conversion 182 ct_buffer = ct.c_char_p(bytes_input_file) 183 ct_buffer_length = ct.c_size_t(len(bytes_input_file)) 184 185 # API call 186 file_type = self.library.GW2DetermineFileTypeFromMemory( 187 ct_buffer, 188 ct_buffer_length 189 ) 190 191 else: 192 raise TypeError(input_file) 193 194 file_type_as_string = dft.file_type_int_to_str(file_type) 195 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 196 197 if not dft.is_success(file_type): 198 log.warning(f"\n\tfile_type: {file_type}\n\tfile_type_as_string: {file_type_as_string}\n\tinput_file: {input_file_repr}") 199 if raise_unsupported: 200 raise dft.int_class_map.get(file_type, dft.errors.UnknownErrorCode)(file_type) 201 else: 202 log.debug(f"\n\tfile_type: {file_type}\n\tfile_type_as_string: {file_type_as_string}\n\tinput_file: {input_file_repr}") 203 204 if as_string: 205 return file_type_as_string 206 207 return file_type 208 209 def _GW2GetPolicySettings(self, session: int, policy_format: int = 0): 210 """ Get current policy settings for the given session. 211 212 Args: 213 session (int): The session integer. 214 policy_format (int): The format of the content management policy. 0=XML. 215 216 Returns: 217 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status', 'policy'. 218 """ 219 # API function declaration 220 self.library.GW2GetPolicySettings.argtypes = [ 221 ct.c_size_t, # Session_Handle session 222 ct.POINTER(ct.c_void_p), # char ** policiesBuffer 223 ct.POINTER(ct.c_size_t), # size_t * policiesLength 224 ct.c_int, # Policy_Format format 225 ] 226 227 # Variable initialisation 228 gw_return_object = glasswall.GwReturnObj() 229 gw_return_object.session = ct.c_size_t(session) 230 gw_return_object.buffer = ct.c_void_p() 231 gw_return_object.buffer_length = ct.c_size_t() 232 gw_return_object.policy_format = ct.c_int(policy_format) 233 234 # API Call 235 gw_return_object.status = self.library.GW2GetPolicySettings( 236 gw_return_object.session, 237 ct.byref(gw_return_object.buffer), 238 ct.byref(gw_return_object.buffer_length), 239 gw_return_object.policy_format 240 ) 241 242 # Editor wrote to a buffer, convert it to bytes 243 policy_bytes = utils.buffer_to_bytes( 244 gw_return_object.buffer, 245 gw_return_object.buffer_length 246 ) 247 248 gw_return_object.policy = policy_bytes.decode() 249 250 return gw_return_object 251 252 def get_content_management_policy(self, session: int): 253 """ Returns the content management configuration for a given session. 254 255 Args: 256 session (int): The session integer. 257 258 Returns: 259 xml_string (str): The XML string of the current content management configuration. 260 """ 261 # NOTE GW2GetPolicySettings is current not implemented in editor 262 263 # set xml_string as loaded default config 264 xml_string = glasswall.content_management.policies.Editor(default="sanitise").text, 265 266 # log.debug(f"xml_string:\n{xml_string}") 267 268 return xml_string 269 270 # # API function declaration 271 # self.library.GW2GetPolicySettings.argtypes = [ 272 # ct.c_size_t, 273 # ct.c_void_p, 274 # ] 275 276 # # Variable initialisation 277 # ct_session = ct.c_size_t(session) 278 # ct_buffer = ct.c_void_p() 279 # ct_buffer_length = ct.c_size_t() 280 # # ct_file_format = ct.c_int(file_format) 281 282 # # API Call 283 # status = self.library.GW2GetPolicySettings( 284 # ct_session, 285 # ct.byref(ct_buffer), 286 # ct.byref(ct_buffer_length) 287 # ) 288 289 # print("GW2GetPolicySettings status:", status) 290 291 # file_bytes = utils.buffer_to_bytes( 292 # ct_buffer, 293 # ct_buffer_length, 294 # ) 295 296 # return file_bytes 297 298 def _GW2RegisterPoliciesFile(self, session: int, input_file: str, policy_format: int = 0): 299 """ Registers the policies to be used by Glasswall when processing files. 300 301 Args: 302 session (int): The session integer. 303 input_file (str): The content management policy input file path. 304 policy_format (int): The format of the content management policy. 0=XML. 305 306 Returns: 307 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'policy_format', 'status'. 308 """ 309 # API function declaration 310 self.library.GW2RegisterPoliciesFile.argtypes = [ 311 ct.c_size_t, # Session_Handle session 312 ct.c_char_p, # const char *filename 313 ct.c_int, # Policy_Format format 314 ] 315 316 # Variable initialisation 317 gw_return_object = glasswall.GwReturnObj() 318 gw_return_object.session = ct.c_size_t(session) 319 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 320 gw_return_object.policy_format = ct.c_int(policy_format) 321 322 gw_return_object.status = self.library.GW2RegisterPoliciesFile( 323 gw_return_object.session, 324 gw_return_object.input_file, 325 gw_return_object.policy_format 326 ) 327 328 return gw_return_object 329 330 def _GW2RegisterPoliciesMemory(self, session: int, input_file: bytes, policy_format: int = 0): 331 """ Registers the policies in memory to be used by Glasswall when processing files. 332 333 Args: 334 session (int): The session integer. 335 input_file (str): The content management policy input file bytes. 336 policy_format (int): The format of the content management policy. 0=XML. 337 338 Returns: 339 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status'. 340 """ 341 # API function declaration 342 self.library.GW2RegisterPoliciesMemory.argtype = [ 343 ct.c_size_t, # Session_Handle session 344 ct.c_char_p, # const char *policies 345 ct.c_size_t, # size_t policiesLength 346 ct.c_int # Policy_Format format 347 ] 348 349 # Variable initialisation 350 gw_return_object = glasswall.GwReturnObj() 351 gw_return_object.session = ct.c_size_t(session) 352 gw_return_object.buffer = ct.c_char_p(input_file) 353 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 354 gw_return_object.policy_format = ct.c_int(policy_format) 355 356 # API Call 357 gw_return_object.status = self.library.GW2RegisterPoliciesMemory( 358 gw_return_object.session, 359 gw_return_object.buffer, 360 gw_return_object.buffer_length, 361 gw_return_object.policy_format 362 ) 363 364 return gw_return_object 365 366 def set_content_management_policy(self, session: int, input_file: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, policy_format=0): 367 """ Sets the content management policy configuration. If input_file is None then default settings (sanitise) are applied. 368 369 Args: 370 session (int): The session integer. 371 input_file (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 372 policy_format (int): The format of the content management policy. 0=XML. 373 374 Returns: 375 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 376 - If input_file is a str file path: 377 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'policy_format', 'status'. 378 379 - If input_file is a file in memory: 380 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status'. 381 """ 382 # Validate type 383 if not isinstance(session, int): 384 raise TypeError(session) 385 if not isinstance(input_file, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 386 raise TypeError(input_file) 387 if not isinstance(policy_format, int): 388 raise TypeError(policy_format) 389 390 # Set input_file to default if input_file is None 391 if input_file is None: 392 input_file = glasswall.content_management.policies.Editor(default="sanitise") 393 394 # Validate xml content is parsable 395 utils.validate_xml(input_file) 396 397 # From file 398 if isinstance(input_file, str) and os.path.isfile(input_file): 399 input_file = os.path.abspath(input_file) 400 401 result = self._GW2RegisterPoliciesFile(session, input_file) 402 403 # From memory 404 elif isinstance(input_file, (str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 405 # Convert bytearray, io.BytesIO to bytes 406 if isinstance(input_file, (bytearray, io.BytesIO)): 407 input_file = utils.as_bytes(input_file) 408 # Convert string xml or Policy to bytes 409 if isinstance(input_file, (str, glasswall.content_management.policies.policy.Policy)): 410 input_file = input_file.encode("utf-8") 411 412 result = self._GW2RegisterPoliciesMemory(session, input_file) 413 414 if result.status not in successes.success_codes: 415 log.error(format_object(result)) 416 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 417 else: 418 log.debug(format_object(result)) 419 420 return result 421 422 def _GW2RegisterInputFile(self, session: int, input_file: str): 423 """ Register an input file for the given session. 424 425 Args: 426 session (int): The session integer. 427 input_file (str): The input file path. 428 429 Returns: 430 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 431 """ 432 # API function declaration 433 self.library.GW2RegisterInputFile.argtypes = [ 434 ct.c_size_t, # Session_Handle session 435 ct.c_char_p # const char * inputFilePath 436 ] 437 438 # Variable initialisation 439 gw_return_object = glasswall.GwReturnObj() 440 gw_return_object.session = ct.c_size_t(session) 441 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 442 gw_return_object.input_file_path = input_file 443 444 # API call 445 gw_return_object.status = self.library.GW2RegisterInputFile( 446 gw_return_object.session, 447 gw_return_object.input_file 448 ) 449 450 return gw_return_object 451 452 def _GW2RegisterInputMemory(self, session: int, input_file: bytes): 453 """ Register an input file in memory for the given session. 454 455 Args: 456 session (int): The session integer. 457 input_file (bytes): The input file in memory. 458 459 Returns: 460 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 461 """ 462 # API function declaration 463 self.library.GW2RegisterInputMemory.argtypes = [ 464 ct.c_size_t, # Session_Handle session 465 ct.c_char_p, # const char * inputFileBuffer 466 ct.c_size_t, # size_t inputLength 467 ] 468 469 # Variable initialisation 470 gw_return_object = glasswall.GwReturnObj() 471 gw_return_object.session = ct.c_size_t(session) 472 gw_return_object.buffer = ct.c_char_p(input_file) 473 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 474 475 # API call 476 gw_return_object.status = self.library.GW2RegisterInputMemory( 477 gw_return_object.session, 478 gw_return_object.buffer, 479 gw_return_object.buffer_length 480 ) 481 482 return gw_return_object 483 484 def register_input(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 485 """ Register an input file or bytes for the given session. 486 487 Args: 488 session (int): The session integer. 489 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 490 491 Returns: 492 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 493 - If input_file is a str file path: 494 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 495 496 - If input_file is a file in memory: 497 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 498 """ 499 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO,)): 500 raise TypeError(input_file) 501 502 if isinstance(input_file, str): 503 if not os.path.isfile(input_file): 504 raise FileNotFoundError(input_file) 505 506 input_file = os.path.abspath(input_file) 507 508 result = self._GW2RegisterInputFile(session, input_file) 509 510 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 511 # Convert bytearray and io.BytesIO to bytes 512 input_file = utils.as_bytes(input_file) 513 514 result = self._GW2RegisterInputMemory(session, input_file) 515 516 if result.status not in successes.success_codes: 517 log.error(format_object(result)) 518 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 519 else: 520 log.debug(format_object(result)) 521 522 return result 523 524 def _GW2RegisterOutFile(self, session: int, output_file: str): 525 """ Register an output file for the given session. 526 527 Args: 528 session (int): The session integer. 529 output_file (str): The output file path. 530 531 Returns: 532 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 533 """ 534 # API function declaration 535 self.library.GW2RegisterOutFile.argtypes = [ 536 ct.c_size_t, # Session_Handle session 537 ct.c_char_p # const char * outputFilePath 538 ] 539 540 # Variable initialisation 541 gw_return_object = glasswall.GwReturnObj() 542 gw_return_object.session = ct.c_size_t(session) 543 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 544 545 # API call 546 gw_return_object.status = self.library.GW2RegisterOutFile( 547 gw_return_object.session, 548 gw_return_object.output_file 549 ) 550 551 return gw_return_object 552 553 def _GW2RegisterOutputMemory(self, session: int): 554 """ Register an output file in memory for the given session. 555 556 Args: 557 session (int): The session integer. 558 559 Returns: 560 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 561 """ 562 # API function declaration 563 self.library.GW2RegisterOutputMemory.argtypes = [ 564 ct.c_size_t, # Session_Handle session 565 ct.POINTER(ct.c_void_p), # char ** outputBuffer 566 ct.POINTER(ct.c_size_t) # size_t * outputLength 567 ] 568 569 # Variable initialisation 570 gw_return_object = glasswall.GwReturnObj() 571 gw_return_object.session = ct.c_size_t(session) 572 gw_return_object.buffer = ct.c_void_p() 573 gw_return_object.buffer_length = ct.c_size_t() 574 575 # API call 576 gw_return_object.status = self.library.GW2RegisterOutputMemory( 577 gw_return_object.session, 578 ct.byref(gw_return_object.buffer), 579 ct.byref(gw_return_object.buffer_length) 580 ) 581 582 return gw_return_object 583 584 def register_output(self, session, output_file: Optional[str] = None): 585 """ Register an output file for the given session. If output_file is None the file will be returned as 'buffer' and 'buffer_length' attributes. 586 587 Args: 588 session (int): The session integer. 589 output_file (Optional[str]): If specified, during run session the file will be written to output_file, otherwise the file will be written to the glasswall.GwReturnObj 'buffer' and 'buffer_length' attributes. 590 591 Returns: 592 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 593 """ 594 if not isinstance(output_file, (type(None), str)): 595 raise TypeError(output_file) 596 597 if isinstance(output_file, str): 598 output_file = os.path.abspath(output_file) 599 600 result = self._GW2RegisterOutFile(session, output_file) 601 602 elif isinstance(output_file, type(None)): 603 result = self._GW2RegisterOutputMemory(session) 604 605 if result.status not in successes.success_codes: 606 log.error(format_object(result)) 607 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 608 else: 609 log.debug(format_object(result)) 610 611 return result 612 613 def _GW2RegisterAnalysisFile(self, session: int, output_file: str, analysis_format: int = 0): 614 """ Register an analysis output file for the given session. 615 616 Args: 617 session (int): The session integer. 618 output_file (str): The analysis output file path. 619 analysis_format (int): The format of the analysis report. 0=XML, 1=XMLExtended 620 621 Returns: 622 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'analysis_format', 'status'. 623 """ 624 # API function declaration 625 self.library.GW2RegisterAnalysisFile.argtypes = [ 626 ct.c_size_t, # Session_Handle session 627 ct.c_char_p, # const char * analysisFilePathName 628 ct.c_int, # Analysis_Format format 629 ] 630 631 # Variable initialisation 632 gw_return_object = glasswall.GwReturnObj() 633 gw_return_object.session = ct.c_size_t(session) 634 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 635 gw_return_object.analysis_format = ct.c_int() 636 637 # API call 638 gw_return_object.status = self.library.GW2RegisterAnalysisFile( 639 gw_return_object.session, 640 gw_return_object.output_file, 641 gw_return_object.analysis_format 642 ) 643 644 return gw_return_object 645 646 def _GW2RegisterAnalysisMemory(self, session: int, analysis_format: int = 0): 647 """ Register an analysis output file in memory for the given session. 648 649 Args: 650 session (int): The session integer. 651 analysis_format (int): The format of the analysis report. 0=XML, 1=XMLExtended 652 653 Returns: 654 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'analysis_format', 'status'. 655 """ 656 # API function declaration 657 self.library.GW2RegisterAnalysisMemory.argtypes = [ 658 ct.c_size_t, # Session_Handle session 659 ct.POINTER(ct.c_void_p), # char ** analysisFileBuffer 660 ct.POINTER(ct.c_size_t), # size_t * analysisoutputLength 661 ct.c_int # Analysis_Format format 662 ] 663 664 # Variable initialisation 665 gw_return_object = glasswall.GwReturnObj() 666 gw_return_object.session = ct.c_size_t(session) 667 gw_return_object.buffer = ct.c_void_p() 668 gw_return_object.buffer_length = ct.c_size_t() 669 gw_return_object.analysis_format = ct.c_int() 670 671 # API call 672 gw_return_object.status = self.library.GW2RegisterAnalysisMemory( 673 gw_return_object.session, 674 ct.byref(gw_return_object.buffer), 675 ct.byref(gw_return_object.buffer_length), 676 gw_return_object.analysis_format 677 ) 678 679 return gw_return_object 680 681 def register_analysis(self, session: int, output_file: Optional[str] = None): 682 """ Registers an analysis file for the given session. The analysis file will be created during the session's run_session call. 683 684 Args: 685 session (int): The session integer. 686 output_file (Optional[str]): Default None. The file path where the analysis will be written. None returns the analysis as bytes. 687 688 Returns: 689 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'status', 'session', 'analysis_format'. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. If output_file is not None (file mode) 'output_file' is included. 690 """ 691 if not isinstance(output_file, (type(None), str)): 692 raise TypeError(output_file) 693 694 if isinstance(output_file, str): 695 output_file = os.path.abspath(output_file) 696 697 result = self._GW2RegisterAnalysisFile(session, output_file) 698 699 elif isinstance(output_file, type(None)): 700 result = self._GW2RegisterAnalysisMemory(session) 701 702 if result.status not in successes.success_codes: 703 log.error(format_object(result)) 704 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 705 else: 706 log.debug(format_object(result)) 707 708 return result 709 710 def protect_file( 711 self, 712 input_file: Union[str, bytes, bytearray, io.BytesIO], 713 output_file: Optional[str] = None, 714 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 715 raise_unsupported: bool = True, 716 ): 717 """ Protects a file using the current content management configuration, returning the file bytes. The protected file is written to output_file if it is provided. 718 719 Args: 720 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 721 output_file (Optional[str]): The output file path where the protected file will be written. 722 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 723 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 724 725 Returns: 726 file_bytes (bytes): The protected file bytes. 727 """ 728 # Validate arg types 729 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 730 raise TypeError(input_file) 731 if not isinstance(output_file, (type(None), str)): 732 raise TypeError(output_file) 733 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 734 raise TypeError(content_management_policy) 735 if not isinstance(raise_unsupported, bool): 736 raise TypeError(raise_unsupported) 737 738 # Convert string path arguments to absolute paths 739 if isinstance(input_file, str): 740 if not os.path.isfile(input_file): 741 raise FileNotFoundError(input_file) 742 input_file = os.path.abspath(input_file) 743 if isinstance(output_file, str): 744 output_file = os.path.abspath(output_file) 745 # make directories that do not exist 746 os.makedirs(os.path.dirname(output_file), exist_ok=True) 747 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 748 content_management_policy = os.path.abspath(content_management_policy) 749 750 # Convert memory inputs to bytes 751 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 752 input_file = utils.as_bytes(input_file) 753 754 with utils.CwdHandler(self.library_path): 755 with self.new_session() as session: 756 content_management_policy = self.set_content_management_policy(session, content_management_policy) 757 register_input = self.register_input(session, input_file) 758 register_output = self.register_output(session, output_file=output_file) 759 status = self.run_session(session) 760 761 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 762 if status not in successes.success_codes: 763 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 764 if raise_unsupported: 765 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 766 else: 767 file_bytes = None 768 else: 769 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 770 # Get file bytes 771 if isinstance(output_file, str): 772 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 773 if not os.path.isfile(output_file): 774 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 775 file_bytes = None 776 else: 777 with open(output_file, "rb") as f: 778 file_bytes = f.read() 779 else: 780 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 781 file_bytes = utils.buffer_to_bytes( 782 register_output.buffer, 783 register_output.buffer_length 784 ) 785 786 # Ensure memory allocated is not garbage collected 787 content_management_policy, register_input, register_output 788 789 return file_bytes 790 791 def protect_directory( 792 self, 793 input_directory: str, 794 output_directory: Optional[str] = None, 795 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 796 raise_unsupported: bool = True, 797 ): 798 """ Recursively processes all files in a directory in protect mode using the given content management policy. 799 The protected files are written to output_directory maintaining the same directory structure as input_directory. 800 801 Args: 802 input_directory (str): The input directory containing files to protect. 803 output_directory (Optional[str]): The output directory where the protected file will be written, or None to not write files. 804 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 805 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 806 807 Returns: 808 protected_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 809 """ 810 protected_files_dict = {} 811 # Call protect_file on each file in input_directory to output_directory 812 for input_file in utils.list_file_paths(input_directory): 813 relative_path = os.path.relpath(input_file, input_directory) 814 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 815 816 protected_bytes = self.protect_file( 817 input_file=input_file, 818 output_file=output_file, 819 raise_unsupported=raise_unsupported, 820 content_management_policy=content_management_policy, 821 ) 822 823 protected_files_dict[relative_path] = protected_bytes 824 825 return protected_files_dict 826 827 def analyse_file( 828 self, 829 input_file: Union[str, bytes, bytearray, io.BytesIO], 830 output_file: Optional[str] = None, 831 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 832 raise_unsupported: bool = True, 833 ): 834 """ Analyses a file, returning the analysis bytes. The analysis is written to output_file if it is provided. 835 836 Args: 837 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 838 output_file (Optional[str]): The output file path where the analysis file will be written. 839 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 840 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 841 842 Returns: 843 file_bytes (bytes): The analysis file bytes. 844 """ 845 # Validate arg types 846 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 847 raise TypeError(input_file) 848 if not isinstance(output_file, (type(None), str)): 849 raise TypeError(output_file) 850 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 851 raise TypeError(content_management_policy) 852 if not isinstance(raise_unsupported, bool): 853 raise TypeError(raise_unsupported) 854 855 # Convert string path arguments to absolute paths 856 if isinstance(input_file, str): 857 if not os.path.isfile(input_file): 858 raise FileNotFoundError(input_file) 859 input_file = os.path.abspath(input_file) 860 if isinstance(output_file, str): 861 output_file = os.path.abspath(output_file) 862 # make directories that do not exist 863 os.makedirs(os.path.dirname(output_file), exist_ok=True) 864 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 865 content_management_policy = os.path.abspath(content_management_policy) 866 867 # Convert memory inputs to bytes 868 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 869 input_file = utils.as_bytes(input_file) 870 871 with utils.CwdHandler(self.library_path): 872 with self.new_session() as session: 873 content_management_policy = self.set_content_management_policy(session, content_management_policy) 874 register_input = self.register_input(session, input_file) 875 register_analysis = self.register_analysis(session, output_file) 876 status = self.run_session(session) 877 878 file_bytes = None 879 if isinstance(output_file, str): 880 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 881 if os.path.isfile(output_file): 882 with open(output_file, "rb") as f: 883 file_bytes = f.read() 884 else: 885 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 886 if register_analysis.buffer and register_analysis.buffer_length: 887 file_bytes = utils.buffer_to_bytes( 888 register_analysis.buffer, 889 register_analysis.buffer_length 890 ) 891 892 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 893 if status not in successes.success_codes: 894 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 895 if raise_unsupported: 896 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 897 else: 898 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 899 900 # Ensure memory allocated is not garbage collected 901 content_management_policy, register_input, register_analysis 902 903 return file_bytes 904 905 def analyse_directory( 906 self, 907 input_directory: str, 908 output_directory: Optional[str] = None, 909 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 910 raise_unsupported: bool = True, 911 ): 912 """ Analyses all files in a directory and its subdirectories. The analysis files are written to output_directory maintaining the same directory structure as input_directory. 913 914 Args: 915 input_directory (str): The input directory containing files to analyse. 916 output_directory (Optional[str]): The output directory where the analysis files will be written, or None to not write files. 917 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 918 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 919 920 Returns: 921 analysis_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 922 """ 923 analysis_files_dict = {} 924 # Call analyse_file on each file in input_directory to output_directory 925 for input_file in utils.list_file_paths(input_directory): 926 relative_path = os.path.relpath(input_file, input_directory) + ".xml" 927 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 928 929 analysis_bytes = self.analyse_file( 930 input_file=input_file, 931 output_file=output_file, 932 raise_unsupported=raise_unsupported, 933 content_management_policy=content_management_policy, 934 ) 935 936 analysis_files_dict[relative_path] = analysis_bytes 937 938 return analysis_files_dict 939 940 def protect_and_analyse_file( 941 self, 942 input_file: Union[str, bytes, bytearray, io.BytesIO], 943 output_file: Optional[str] = None, 944 output_analysis_report: Optional[str] = None, 945 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 946 raise_unsupported: bool = True, 947 ): 948 """ Protects and analyses a file in a single session, returning both protected file bytes and analysis report bytes. 949 950 Args: 951 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 952 output_file (Optional[str]): The output file path where the protected file will be written. 953 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 954 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 955 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 956 957 Returns: 958 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (protected_file_bytes, analysis_report_bytes). 959 """ 960 # Validate arg types 961 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 962 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 963 if not isinstance(output_file, (type(None), str)): 964 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 965 if not isinstance(output_analysis_report, (type(None), str)): 966 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 967 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 968 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 969 if not isinstance(raise_unsupported, bool): 970 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 971 972 # Convert string path arguments to absolute paths 973 if isinstance(input_file, str): 974 if not os.path.isfile(input_file): 975 raise FileNotFoundError(input_file) 976 input_file = os.path.abspath(input_file) 977 if isinstance(output_file, str): 978 output_file = os.path.abspath(output_file) 979 os.makedirs(os.path.dirname(output_file), exist_ok=True) 980 if isinstance(output_analysis_report, str): 981 output_analysis_report = os.path.abspath(output_analysis_report) 982 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 983 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 984 content_management_policy = os.path.abspath(content_management_policy) 985 986 # Convert memory inputs to bytes 987 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 988 input_file = utils.as_bytes(input_file) 989 990 with utils.CwdHandler(self.library_path): 991 with self.new_session() as session: 992 content_management_policy = self.set_content_management_policy(session, content_management_policy) 993 register_input = self.register_input(session, input_file) 994 register_output = self.register_output(session, output_file) 995 register_analysis = self.register_analysis(session, output_analysis_report) 996 997 status = self.run_session(session) 998 999 protected_file_bytes = None 1000 analysis_report_bytes = None 1001 1002 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1003 if status not in successes.success_codes: 1004 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1005 if raise_unsupported: 1006 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1007 1008 # Get analysis report file bytes, even on processing failure 1009 if isinstance(output_analysis_report, str): 1010 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1011 if not os.path.isfile(output_analysis_report): 1012 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1013 else: 1014 with open(output_analysis_report, "rb") as f: 1015 analysis_report_bytes = f.read() 1016 else: 1017 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1018 if register_analysis.buffer and register_analysis.buffer_length: 1019 analysis_report_bytes = utils.buffer_to_bytes( 1020 register_analysis.buffer, 1021 register_analysis.buffer_length 1022 ) 1023 1024 # On success, get protected file bytes 1025 if status in successes.success_codes: 1026 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1027 # Get file bytes 1028 if isinstance(output_file, str): 1029 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1030 if not os.path.isfile(output_file): 1031 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1032 else: 1033 with open(output_file, "rb") as f: 1034 protected_file_bytes = f.read() 1035 else: 1036 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1037 protected_file_bytes = utils.buffer_to_bytes( 1038 register_output.buffer, 1039 register_output.buffer_length 1040 ) 1041 1042 # Ensure memory allocated is not garbage collected 1043 content_management_policy, register_input, register_output, register_analysis 1044 1045 return protected_file_bytes, analysis_report_bytes 1046 1047 def protect_and_analyse_directory( 1048 self, 1049 input_directory: str, 1050 output_directory: Optional[str] = None, 1051 analysis_directory: Optional[str] = None, 1052 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1053 raise_unsupported: bool = True, 1054 ): 1055 """ Recursively processes all files in a directory using protect and analyse mode with the given content management policy. 1056 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1057 1058 Args: 1059 input_directory (str): The input directory containing files to process. 1060 output_directory (Optional[str]): The output directory for protected files. 1061 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1062 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1063 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1064 1065 Returns: 1066 result_dict (dict): A dictionary mapping relative file paths to tuples of (protected_file_bytes, analysis_report_bytes). 1067 """ 1068 result_dict = {} 1069 for input_file in utils.list_file_paths(input_directory): 1070 relative_path = os.path.relpath(input_file, input_directory) 1071 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1072 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1073 1074 protected_file_bytes, analysis_report_bytes = self.protect_and_analyse_file( 1075 input_file=input_file, 1076 output_file=output_file, 1077 output_analysis_report=output_analysis_report, 1078 content_management_policy=content_management_policy, 1079 raise_unsupported=raise_unsupported, 1080 ) 1081 1082 result_dict[relative_path] = (protected_file_bytes, analysis_report_bytes) 1083 1084 return result_dict 1085 1086 def _GW2RegisterExportFile(self, session: int, output_file: str): 1087 """ Register an export output file for the given session. 1088 1089 Args: 1090 session (int): The session integer. 1091 output_file (str): The export output file path. 1092 1093 Returns: 1094 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 1095 """ 1096 # API function declaration 1097 self.library.GW2RegisterExportFile.argtypes = [ 1098 ct.c_size_t, # Session_Handle session 1099 ct.c_char_p # const char * exportFilePath 1100 ] 1101 1102 # Variable initialisation 1103 gw_return_object = glasswall.GwReturnObj() 1104 gw_return_object.session = ct.c_size_t(session) 1105 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 1106 1107 # API Call 1108 gw_return_object.status = self.library.GW2RegisterExportFile( 1109 gw_return_object.session, 1110 gw_return_object.output_file 1111 ) 1112 1113 return gw_return_object 1114 1115 def _GW2RegisterExportMemory(self, session: int): 1116 """ Register an export output file in memory for the given session. 1117 1118 Args: 1119 session (int): The session integer. 1120 1121 Returns: 1122 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 1123 """ 1124 # API function declaration 1125 self.library.GW2RegisterExportMemory.argtypes = [ 1126 ct.c_size_t, # Session_Handle session 1127 ct.POINTER(ct.c_void_p), # char ** exportFileBuffer 1128 ct.POINTER(ct.c_size_t) # size_t * exportLength 1129 ] 1130 1131 # Variable initialisation 1132 gw_return_object = glasswall.GwReturnObj() 1133 gw_return_object.session = ct.c_size_t(session) 1134 gw_return_object.buffer = ct.c_void_p() 1135 gw_return_object.buffer_length = ct.c_size_t() 1136 1137 # API call 1138 gw_return_object.status = self.library.GW2RegisterExportMemory( 1139 gw_return_object.session, 1140 ct.byref(gw_return_object.buffer), 1141 ct.byref(gw_return_object.buffer_length) 1142 ) 1143 1144 return gw_return_object 1145 1146 def register_export(self, session: int, output_file: Optional[str] = None): 1147 """ Registers a file to be exported for the given session. The export file will be created during the session's run_session call. 1148 1149 Args: 1150 session (int): The session integer. 1151 output_file (Optional[str]): Default None. The file path where the export will be written. None exports the file in memory. 1152 1153 Returns: 1154 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call and 'session', the session integer. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 1155 """ 1156 if not isinstance(output_file, (type(None), str)): 1157 raise TypeError(output_file) 1158 1159 if isinstance(output_file, str): 1160 output_file = os.path.abspath(output_file) 1161 1162 result = self._GW2RegisterExportFile(session, output_file) 1163 1164 elif isinstance(output_file, type(None)): 1165 result = self._GW2RegisterExportMemory(session) 1166 1167 if result.status not in successes.success_codes: 1168 log.error(format_object(result)) 1169 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1170 else: 1171 log.debug(format_object(result)) 1172 1173 return result 1174 1175 def export_file( 1176 self, 1177 input_file: Union[str, bytes, bytearray, io.BytesIO], 1178 output_file: Optional[str] = None, 1179 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1180 raise_unsupported: bool = True, 1181 ): 1182 """ Export a file, returning the .zip file bytes. The .zip file is written to output_file if it is provided. 1183 1184 Args: 1185 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1186 output_file (Optional[str]): The output file path where the .zip file will be written. 1187 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1188 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1189 1190 Returns: 1191 file_bytes (bytes): The exported .zip file. 1192 """ 1193 # Validate arg types 1194 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1195 raise TypeError(input_file) 1196 if not isinstance(output_file, (type(None), str)): 1197 raise TypeError(output_file) 1198 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1199 raise TypeError(content_management_policy) 1200 if not isinstance(raise_unsupported, bool): 1201 raise TypeError(raise_unsupported) 1202 1203 # Convert string path arguments to absolute paths 1204 if isinstance(input_file, str): 1205 if not os.path.isfile(input_file): 1206 raise FileNotFoundError(input_file) 1207 input_file = os.path.abspath(input_file) 1208 if isinstance(output_file, str): 1209 output_file = os.path.abspath(output_file) 1210 # make directories that do not exist 1211 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1212 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1213 content_management_policy = os.path.abspath(content_management_policy) 1214 1215 # Convert memory inputs to bytes 1216 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1217 input_file = utils.as_bytes(input_file) 1218 1219 with utils.CwdHandler(self.library_path): 1220 with self.new_session() as session: 1221 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1222 register_input = self.register_input(session, input_file) 1223 register_export = self.register_export(session, output_file) 1224 status = self.run_session(session) 1225 1226 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1227 if status not in successes.success_codes: 1228 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1229 if raise_unsupported: 1230 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1231 else: 1232 file_bytes = None 1233 else: 1234 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1235 # Get file bytes 1236 if isinstance(output_file, str): 1237 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1238 if not os.path.isfile(output_file): 1239 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1240 file_bytes = None 1241 else: 1242 with open(output_file, "rb") as f: 1243 file_bytes = f.read() 1244 else: 1245 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1246 file_bytes = utils.buffer_to_bytes( 1247 register_export.buffer, 1248 register_export.buffer_length 1249 ) 1250 1251 # Ensure memory allocated is not garbage collected 1252 content_management_policy, register_input, register_export 1253 1254 return file_bytes 1255 1256 def export_directory( 1257 self, 1258 input_directory: str, 1259 output_directory: Optional[str] = None, 1260 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1261 raise_unsupported: bool = True 1262 ): 1263 """ Exports all files in a directory and its subdirectories. The export files are written to output_directory maintaining the same directory structure as input_directory. 1264 1265 Args: 1266 input_directory (str): The input directory containing files to export. 1267 output_directory (Optional[str]): The output directory where the export files will be written, or None to not write files. 1268 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 1269 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1270 1271 Returns: 1272 export_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 1273 """ 1274 export_files_dict = {} 1275 # Call export_file on each file in input_directory to output_directory 1276 for input_file in utils.list_file_paths(input_directory): 1277 relative_path = os.path.relpath(input_file, input_directory) + ".zip" 1278 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1279 1280 export_bytes = self.export_file( 1281 input_file=input_file, 1282 output_file=output_file, 1283 raise_unsupported=raise_unsupported, 1284 content_management_policy=content_management_policy, 1285 ) 1286 1287 export_files_dict[relative_path] = export_bytes 1288 1289 return export_files_dict 1290 1291 def export_and_analyse_file( 1292 self, 1293 input_file: Union[str, bytes, bytearray, io.BytesIO], 1294 output_file: Optional[str] = None, 1295 output_analysis_report: Optional[str] = None, 1296 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1297 raise_unsupported: bool = True, 1298 ): 1299 """ Exports and analyses a file in a single session, returning both exported .zip bytes and analysis report bytes. 1300 1301 Args: 1302 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1303 output_file (Optional[str]): The output file path where the .zip export will be written. 1304 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 1305 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1306 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1307 1308 Returns: 1309 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (export_file_bytes, analysis_report_bytes). 1310 """ 1311 # Validate arg types 1312 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1313 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 1314 if not isinstance(output_file, (type(None), str)): 1315 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 1316 if not isinstance(output_analysis_report, (type(None), str)): 1317 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 1318 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1319 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 1320 if not isinstance(raise_unsupported, bool): 1321 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 1322 1323 # Convert string path arguments to absolute paths 1324 if isinstance(input_file, str): 1325 if not os.path.isfile(input_file): 1326 raise FileNotFoundError(input_file) 1327 input_file = os.path.abspath(input_file) 1328 if isinstance(output_file, str): 1329 output_file = os.path.abspath(output_file) 1330 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1331 if isinstance(output_analysis_report, str): 1332 output_analysis_report = os.path.abspath(output_analysis_report) 1333 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 1334 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1335 content_management_policy = os.path.abspath(content_management_policy) 1336 1337 # Convert memory inputs to bytes 1338 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1339 input_file = utils.as_bytes(input_file) 1340 1341 with utils.CwdHandler(self.library_path): 1342 with self.new_session() as session: 1343 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1344 register_input = self.register_input(session, input_file) 1345 register_export = self.register_export(session, output_file) 1346 register_analysis = self.register_analysis(session, output_analysis_report) 1347 1348 status = self.run_session(session) 1349 1350 export_file_bytes = None 1351 analysis_report_bytes = None 1352 1353 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1354 if status not in successes.success_codes: 1355 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1356 if raise_unsupported: 1357 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1358 1359 # Get analysis report file bytes, even on processing failure 1360 if isinstance(output_analysis_report, str): 1361 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1362 if not os.path.isfile(output_analysis_report): 1363 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1364 else: 1365 with open(output_analysis_report, "rb") as f: 1366 analysis_report_bytes = f.read() 1367 else: 1368 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1369 if register_analysis.buffer and register_analysis.buffer_length: 1370 analysis_report_bytes = utils.buffer_to_bytes( 1371 register_analysis.buffer, 1372 register_analysis.buffer_length 1373 ) 1374 1375 # On success, get export file bytes 1376 if status in successes.success_codes: 1377 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1378 # Get export file bytes 1379 if isinstance(output_file, str): 1380 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1381 if not os.path.isfile(output_file): 1382 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1383 else: 1384 with open(output_file, "rb") as f: 1385 export_file_bytes = f.read() 1386 else: 1387 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1388 export_file_bytes = utils.buffer_to_bytes( 1389 register_export.buffer, 1390 register_export.buffer_length 1391 ) 1392 1393 # Ensure memory allocated is not garbage collected 1394 content_management_policy, register_input, register_export, register_analysis 1395 1396 return export_file_bytes, analysis_report_bytes 1397 1398 def export_and_analyse_directory( 1399 self, 1400 input_directory: str, 1401 output_directory: Optional[str] = None, 1402 analysis_directory: Optional[str] = None, 1403 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1404 raise_unsupported: bool = True, 1405 ): 1406 """ Recursively processes all files in a directory using export and analyse mode with the given content management policy. 1407 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1408 1409 Args: 1410 input_directory (str): The input directory containing files to process. 1411 output_directory (Optional[str]): The output directory for exported .zip files. 1412 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1413 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1414 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1415 1416 Returns: 1417 result_dict (dict): A dictionary mapping relative file paths to tuples of (export_file_bytes, analysis_report_bytes). 1418 """ 1419 result_dict = {} 1420 1421 for input_file in utils.list_file_paths(input_directory): 1422 relative_path = os.path.relpath(input_file, input_directory) 1423 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path + ".zip") 1424 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1425 1426 export_file_bytes, analysis_report_bytes = self.export_and_analyse_file( 1427 input_file=input_file, 1428 output_file=output_file, 1429 output_analysis_report=output_analysis_report, 1430 content_management_policy=content_management_policy, 1431 raise_unsupported=raise_unsupported, 1432 ) 1433 1434 result_dict[relative_path] = (export_file_bytes, analysis_report_bytes) 1435 1436 return result_dict 1437 1438 def _GW2RegisterImportFile(self, session: int, input_file: str): 1439 """ Register an import input file for the given session. 1440 1441 Args: 1442 session (int): The session integer. 1443 input_file (str): The input import file path. 1444 1445 Returns: 1446 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 1447 """ 1448 # API function declaration 1449 self.library.GW2RegisterImportFile.argtypes = [ 1450 ct.c_size_t, # Session_Handle session 1451 ct.c_char_p # const char * importFilePath 1452 ] 1453 1454 # Variable initialisation 1455 gw_return_object = glasswall.GwReturnObj() 1456 gw_return_object.session = ct.c_size_t(session) 1457 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 1458 1459 # API Call 1460 gw_return_object.status = self.library.GW2RegisterImportFile( 1461 gw_return_object.session, 1462 gw_return_object.input_file 1463 ) 1464 1465 return gw_return_object 1466 1467 def _GW2RegisterImportMemory(self, session: int, input_file: bytes): 1468 """ Register an import input file in memory for the given session. 1469 1470 Args: 1471 session (int): The session integer. 1472 input_file (str): The input import file in memory. 1473 1474 Returns: 1475 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 1476 """ 1477 # API function declaration 1478 self.library.GW2RegisterImportMemory.argtypes = [ 1479 ct.c_size_t, # Session_Handle session 1480 ct.c_void_p, # char * importFileBuffer 1481 ct.c_size_t # size_t importLength 1482 ] 1483 1484 # Variable initialisation 1485 gw_return_object = glasswall.GwReturnObj() 1486 gw_return_object.session = ct.c_size_t(session) 1487 gw_return_object.buffer = ct.c_char_p(input_file) 1488 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 1489 1490 # API call 1491 gw_return_object.status = self.library.GW2RegisterImportMemory( 1492 gw_return_object.session, 1493 gw_return_object.buffer, 1494 gw_return_object.buffer_length 1495 ) 1496 1497 return gw_return_object 1498 1499 def register_import(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 1500 """ Registers a .zip file to be imported for the given session. The constructed file will be created during the session's run_session call. 1501 1502 Args: 1503 session (int): The session integer. 1504 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input import file path or bytes. 1505 1506 Returns: 1507 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 1508 """ 1509 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO,)): 1510 raise TypeError(input_file) 1511 1512 if isinstance(input_file, str): 1513 if not os.path.isfile(input_file): 1514 raise FileNotFoundError(input_file) 1515 1516 input_file = os.path.abspath(input_file) 1517 1518 result = self._GW2RegisterImportFile(session, input_file) 1519 1520 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 1521 # Convert bytearray and io.BytesIO to bytes 1522 input_file = utils.as_bytes(input_file) 1523 1524 result = self._GW2RegisterImportMemory(session, input_file) 1525 1526 if result.status not in successes.success_codes: 1527 log.error(format_object(result)) 1528 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1529 else: 1530 log.debug(format_object(result)) 1531 1532 return result 1533 1534 def import_file( 1535 self, 1536 input_file: Union[str, bytes, bytearray, io.BytesIO], 1537 output_file: Optional[str] = None, 1538 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1539 raise_unsupported: bool = True, 1540 ): 1541 """ Import a .zip file, constructs a file from the .zip file and returns the file bytes. The file is written to output_file if it is provided. 1542 1543 Args: 1544 input_file (Union[str, bytes, bytearray, io.BytesIO]): The .zip input file path or bytes. 1545 output_file (Optional[str]): The output file path where the constructed file will be written. 1546 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1547 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1548 1549 Returns: 1550 file_bytes (bytes): The imported file bytes. 1551 """ 1552 # Validate arg types 1553 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1554 raise TypeError(input_file) 1555 if not isinstance(output_file, (type(None), str)): 1556 raise TypeError(output_file) 1557 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1558 raise TypeError(content_management_policy) 1559 if not isinstance(raise_unsupported, bool): 1560 raise TypeError(raise_unsupported) 1561 1562 # Convert string path arguments to absolute paths 1563 if isinstance(input_file, str): 1564 if not os.path.isfile(input_file): 1565 raise FileNotFoundError(input_file) 1566 input_file = os.path.abspath(input_file) 1567 if isinstance(output_file, str): 1568 output_file = os.path.abspath(output_file) 1569 # make directories that do not exist 1570 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1571 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1572 content_management_policy = os.path.abspath(content_management_policy) 1573 1574 # Convert memory inputs to bytes 1575 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1576 input_file = utils.as_bytes(input_file) 1577 1578 with utils.CwdHandler(self.library_path): 1579 with self.new_session() as session: 1580 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1581 register_import = self.register_import(session, input_file) 1582 register_output = self.register_output(session, output_file) 1583 status = self.run_session(session) 1584 1585 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1586 if status not in successes.success_codes: 1587 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1588 if raise_unsupported: 1589 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1590 else: 1591 file_bytes = None 1592 else: 1593 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1594 # Get file bytes 1595 if isinstance(output_file, str): 1596 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1597 if not os.path.isfile(output_file): 1598 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1599 file_bytes = None 1600 else: 1601 with open(output_file, "rb") as f: 1602 file_bytes = f.read() 1603 else: 1604 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1605 file_bytes = utils.buffer_to_bytes( 1606 register_output.buffer, 1607 register_output.buffer_length 1608 ) 1609 1610 # Ensure memory allocated is not garbage collected 1611 content_management_policy, register_import, register_output 1612 1613 return file_bytes 1614 1615 def import_directory( 1616 self, 1617 input_directory: str, 1618 output_directory: Optional[str] = None, 1619 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1620 raise_unsupported: bool = True, 1621 ): 1622 """ Imports all files in a directory and its subdirectories. Files are expected as .zip but this is not forced. 1623 The constructed files are written to output_directory maintaining the same directory structure as input_directory. 1624 1625 Args: 1626 input_directory (str): The input directory containing files to import. 1627 output_directory (Optional[str]): The output directory where the constructed files will be written, or None to not write files. 1628 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 1629 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1630 1631 Returns: 1632 import_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 1633 """ 1634 import_files_dict = {} 1635 # Call import_file on each file in input_directory to output_directory 1636 for input_file in utils.list_file_paths(input_directory): 1637 relative_path = os.path.relpath(input_file, input_directory) 1638 # Remove .zip extension from relative_path 1639 if relative_path.endswith(".zip"): 1640 relative_path = os.path.splitext(relative_path)[0] 1641 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1642 1643 import_bytes = self.import_file( 1644 input_file=input_file, 1645 output_file=output_file, 1646 raise_unsupported=raise_unsupported, 1647 content_management_policy=content_management_policy, 1648 ) 1649 1650 import_files_dict[relative_path] = import_bytes 1651 1652 return import_files_dict 1653 1654 def import_and_analyse_file( 1655 self, 1656 input_file: Union[str, bytes, bytearray, io.BytesIO], 1657 output_file: Optional[str] = None, 1658 output_analysis_report: Optional[str] = None, 1659 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1660 raise_unsupported: bool = True, 1661 ): 1662 """ Imports and analyses a file in a single session, returning both imported file bytes and analysis report bytes. 1663 1664 Args: 1665 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1666 output_file (Optional[str]): The output file path where the imported file will be written. 1667 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 1668 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1669 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1670 1671 Returns: 1672 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (import_file_bytes, analysis_report_bytes). 1673 """ 1674 # Validate arg types 1675 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1676 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 1677 if not isinstance(output_file, (type(None), str)): 1678 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 1679 if not isinstance(output_analysis_report, (type(None), str)): 1680 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 1681 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1682 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 1683 if not isinstance(raise_unsupported, bool): 1684 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 1685 1686 # Convert string path arguments to absolute paths 1687 if isinstance(input_file, str): 1688 if not os.path.isfile(input_file): 1689 raise FileNotFoundError(input_file) 1690 input_file = os.path.abspath(input_file) 1691 if isinstance(output_file, str): 1692 output_file = os.path.abspath(output_file) 1693 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1694 if isinstance(output_analysis_report, str): 1695 output_analysis_report = os.path.abspath(output_analysis_report) 1696 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 1697 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1698 content_management_policy = os.path.abspath(content_management_policy) 1699 1700 # Convert memory inputs to bytes 1701 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1702 input_file = utils.as_bytes(input_file) 1703 1704 with utils.CwdHandler(self.library_path): 1705 with self.new_session() as session: 1706 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1707 register_import = self.register_import(session, input_file) 1708 register_output = self.register_output(session, output_file) 1709 register_analysis = self.register_analysis(session, output_analysis_report) 1710 1711 status = self.run_session(session) 1712 1713 import_file_bytes = None 1714 analysis_report_bytes = None 1715 1716 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1717 if status not in successes.success_codes: 1718 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1719 if raise_unsupported: 1720 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1721 1722 # Get analysis report file bytes, even on processing failure 1723 if isinstance(output_analysis_report, str): 1724 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1725 if not os.path.isfile(output_analysis_report): 1726 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1727 else: 1728 with open(output_analysis_report, "rb") as f: 1729 analysis_report_bytes = f.read() 1730 else: 1731 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1732 if register_analysis.buffer and register_analysis.buffer_length: 1733 analysis_report_bytes = utils.buffer_to_bytes( 1734 register_analysis.buffer, 1735 register_analysis.buffer_length 1736 ) 1737 1738 # On success, get import file bytes 1739 if status in successes.success_codes: 1740 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1741 # Get import file bytes 1742 if isinstance(output_file, str): 1743 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1744 if not os.path.isfile(output_file): 1745 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1746 else: 1747 with open(output_file, "rb") as f: 1748 import_file_bytes = f.read() 1749 else: 1750 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1751 import_file_bytes = utils.buffer_to_bytes( 1752 register_import.buffer, 1753 register_import.buffer_length 1754 ) 1755 1756 # Ensure memory allocated is not garbage collected 1757 content_management_policy, register_import, register_output, register_analysis 1758 1759 return import_file_bytes, analysis_report_bytes 1760 1761 def import_and_analyse_directory( 1762 self, 1763 input_directory: str, 1764 output_directory: Optional[str] = None, 1765 analysis_directory: Optional[str] = None, 1766 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1767 raise_unsupported: bool = True, 1768 ): 1769 """ Recursively processes all files in a directory using import and analyse mode with the given content management policy. 1770 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1771 1772 Args: 1773 input_directory (str): The input directory containing export .zip files to process. 1774 output_directory (Optional[str]): The output directory for imported files. 1775 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1776 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1777 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1778 1779 Returns: 1780 result_dict (dict): A dictionary mapping relative file paths to tuples of (import_file_bytes, analysis_report_bytes). 1781 """ 1782 result_dict = {} 1783 1784 for input_file in utils.list_file_paths(input_directory): 1785 relative_path = os.path.relpath(input_file, input_directory) 1786 # Remove .zip extension from relative_path 1787 if relative_path.endswith(".zip"): 1788 relative_path = os.path.splitext(relative_path)[0] 1789 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1790 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1791 1792 import_file_bytes, analysis_report_bytes = self.import_and_analyse_file( 1793 input_file=input_file, 1794 output_file=output_file, 1795 output_analysis_report=output_analysis_report, 1796 content_management_policy=content_management_policy, 1797 raise_unsupported=raise_unsupported, 1798 ) 1799 1800 result_dict[relative_path] = (import_file_bytes, analysis_report_bytes) 1801 1802 return result_dict 1803 1804 def _GW2FileErrorMsg(self, session: int): 1805 """ Retrieve the Glasswall Session Process error message. 1806 1807 Args: 1808 session (int): The session integer. 1809 1810 Returns: 1811 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status', 'error_message'. 1812 """ 1813 # API function declaration 1814 self.library.GW2FileErrorMsg.argtypes = [ 1815 ct.c_size_t, # Session_Handle session 1816 ct.POINTER(ct.c_void_p), # char **errorMsgBuffer 1817 ct.POINTER(ct.c_size_t) # size_t *errorMsgBufferLength 1818 ] 1819 1820 # Variable initialisation 1821 gw_return_object = glasswall.GwReturnObj() 1822 gw_return_object.session = ct.c_size_t(session) 1823 gw_return_object.buffer = ct.c_void_p() 1824 gw_return_object.buffer_length = ct.c_size_t() 1825 1826 # API call 1827 gw_return_object.status = self.library.GW2FileErrorMsg( 1828 gw_return_object.session, 1829 ct.byref(gw_return_object.buffer), 1830 ct.byref(gw_return_object.buffer_length) 1831 ) 1832 1833 # Editor wrote to a buffer, convert it to bytes 1834 error_bytes = utils.buffer_to_bytes( 1835 gw_return_object.buffer, 1836 gw_return_object.buffer_length 1837 ) 1838 1839 gw_return_object.error_message = error_bytes.decode() 1840 1841 return gw_return_object 1842 1843 @functools.lru_cache() 1844 def file_error_message(self, session: int) -> str: 1845 """ Retrieve the Glasswall Session Process error message. 1846 1847 Args: 1848 session (int): The session integer. 1849 1850 Returns: 1851 error_message (str): The Glasswall Session Process error message. 1852 """ 1853 # Validate arg types 1854 if not isinstance(session, int): 1855 raise TypeError(session) 1856 1857 result = self._GW2FileErrorMsg(session) 1858 1859 if result.status not in successes.success_codes: 1860 log.error(format_object(result)) 1861 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1862 else: 1863 log.debug(format_object(result)) 1864 1865 return result.error_message 1866 1867 def GW2GetFileType(self, session: int, file_type_id): 1868 """ Retrieve the file type as a string. 1869 1870 Args: 1871 session (int): The session integer. 1872 file_type_id (int): The file type id. 1873 1874 Returns: 1875 file_type (str): The formal file name for the corresponding file id. 1876 """ 1877 # Validate arg types 1878 if not isinstance(session, int): 1879 raise TypeError(session) 1880 1881 # API function declaration 1882 self.library.GW2GetFileType.argtypes = [ 1883 ct.c_size_t, 1884 ct.c_size_t, 1885 ct.POINTER(ct.c_size_t), 1886 ct.POINTER(ct.c_void_p) 1887 ] 1888 1889 # Variable initialisation 1890 ct_session = ct.c_size_t(session) 1891 ct_file_type = ct.c_size_t(file_type_id) 1892 ct_buffer_length = ct.c_size_t() 1893 ct_buffer = ct.c_void_p() 1894 1895 # API call 1896 status = self.library.GW2GetFileType( 1897 ct_session, 1898 ct_file_type, 1899 ct.byref(ct_buffer_length), 1900 ct.byref(ct_buffer) 1901 ) 1902 1903 if status not in successes.success_codes: 1904 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 1905 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1906 else: 1907 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 1908 1909 # Editor wrote to a buffer, convert it to bytes 1910 file_type_bytes = utils.buffer_to_bytes( 1911 ct_buffer, 1912 ct_buffer_length 1913 ) 1914 1915 file_type = file_type_bytes.decode() 1916 1917 return file_type 1918 1919 def GW2GetFileTypeID(self, session: int, file_type_str): 1920 """ Retrieve the Glasswall file type id given a file type string. 1921 1922 Args: 1923 session (int): The session integer. 1924 file_type_str (str): The file type as a string. 1925 1926 Returns: 1927 file_type_id (str): The Glasswall file type id for the specified file type. 1928 """ 1929 # Validate arg types 1930 if not isinstance(session, int): 1931 raise TypeError(session) 1932 1933 # API function declaration 1934 self.library.GW2GetFileTypeID.argtypes = [ 1935 ct.c_size_t, 1936 ct.c_char_p, 1937 ct.POINTER(ct.c_size_t), 1938 ct.POINTER(ct.c_void_p) 1939 ] 1940 1941 # Variable initialisation 1942 ct_session = ct.c_size_t(session) 1943 ct_file_type = ct.c_char_p(file_type_str.encode('utf-8')) 1944 ct_buffer_length = ct.c_size_t() 1945 ct_buffer = ct.c_void_p() 1946 1947 # API call 1948 status = self.library.GW2GetFileTypeID( 1949 ct_session, 1950 ct_file_type, 1951 ct.byref(ct_buffer_length), 1952 ct.byref(ct_buffer) 1953 ) 1954 1955 if status not in successes.success_codes: 1956 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 1957 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1958 else: 1959 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 1960 1961 # Editor wrote to a buffer, convert it to bytes 1962 file_type_bytes = utils.buffer_to_bytes( 1963 ct_buffer, 1964 ct_buffer_length 1965 ) 1966 1967 file_type_id = file_type_bytes.decode() 1968 1969 return file_type_id 1970 1971 def get_file_type_info(self, file_type: Union[str, int]): 1972 """ Retrieve information about a file type based on its identifier. 1973 1974 Args: 1975 file_type (Union[str, int]): The file type identifier. This can be either a string representing a file 1976 extension (e.g. 'bmp') or an integer corresponding to a file type (e.g. 29). 1977 1978 Returns: 1979 - file_type_info (Union[int, str]): Depending on the input 'file_type': 1980 - If `file_type` is a string (e.g. 'bmp'): 1981 - If the file type is recognised, returns an integer corresponding to that file type. 1982 - If the file type is not recognised, returns 0. 1983 - If `file_type` is an integer (e.g. 29): 1984 - If the integer corresponds to a recognised file type, returns a more detailed string description 1985 of the file type (e.g. 'BMP Image'). 1986 - If the integer does not match any recognised file type, returns an empty string. 1987 """ 1988 # Validate arg types 1989 if not isinstance(file_type, (str, int)): 1990 raise TypeError(file_type) 1991 1992 with utils.CwdHandler(self.library_path): 1993 with self.new_session() as session: 1994 1995 if isinstance(file_type, int): 1996 file_type_info = self.GW2GetFileType(session, file_type) 1997 if isinstance(file_type, str): 1998 file_type_info = self.GW2GetFileTypeID(session, file_type) 1999 2000 return file_type_info 2001 2002 @utils.deprecated_function(replacement_function=get_file_type_info) 2003 def get_file_info(self, *args, **kwargs): 2004 """ Deprecated in 1.0.6. Use get_file_type_info. """ 2005 pass 2006 2007 def _GW2RegisterReportFile(self, session: int, output_file: str): 2008 """ Register an output report file path for the given session. 2009 2010 Args: 2011 session (int): The session integer. 2012 output_file (str): The file path of the output report file. 2013 2014 Returns: 2015 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2016 """ 2017 # API function declaration 2018 self.library.GW2RegisterReportFile.argtypes = [ 2019 ct.c_size_t, # Session_Handle session 2020 ct.c_char_p, # const char * reportFilePathName 2021 ] 2022 2023 # Variable initialisation 2024 gw_return_object = glasswall.GwReturnObj() 2025 gw_return_object.session = ct.c_size_t(session) 2026 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 2027 2028 # API call 2029 gw_return_object.status = self.library.GW2RegisterReportFile( 2030 gw_return_object.session, 2031 gw_return_object.output_file 2032 ) 2033 2034 return gw_return_object 2035 2036 def register_report_file(self, session: int, output_file: str): 2037 """ Register the report file path for the given session. 2038 2039 Args: 2040 session (int): The session integer. 2041 output_file (str): The file path of the report file. 2042 2043 Returns: 2044 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2045 """ 2046 # Validate arg types 2047 if not isinstance(session, int): 2048 raise TypeError(session) 2049 if not isinstance(output_file, (type(None), str)): 2050 raise TypeError(output_file) 2051 2052 result = self._GW2RegisterReportFile(session, output_file) 2053 2054 if result.status not in successes.success_codes: 2055 log.error(format_object(result)) 2056 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2057 else: 2058 log.debug(format_object(result)) 2059 2060 return result 2061 2062 def _GW2GetIdInfo(self, session: int, issue_id: int): 2063 """ Retrieves the group description for the given Issue ID. e.g. issue_id 96 returns "Document Processing Instances" 2064 2065 Args: 2066 session (int): The session integer. 2067 issue_id (int): The issue id. 2068 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2069 2070 Returns: 2071 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'issue_id', 'buffer_length', 'buffer', 'status', 'id_info'. 2072 """ 2073 # API function declaration 2074 self.library.GW2GetIdInfo.argtypes = [ 2075 ct.c_size_t, # Session_Handle session 2076 ct.c_size_t, # size_t issueId 2077 ct.POINTER(ct.c_size_t), # size_t * bufferLength 2078 ct.POINTER(ct.c_void_p) # char ** outputBuffer 2079 ] 2080 2081 # Variable initialisation 2082 gw_return_object = glasswall.GwReturnObj() 2083 gw_return_object.session = ct.c_size_t(session) 2084 gw_return_object.issue_id = ct.c_size_t(issue_id) 2085 gw_return_object.buffer_length = ct.c_size_t() 2086 gw_return_object.buffer = ct.c_void_p() 2087 2088 # API call 2089 gw_return_object.status = self.library.GW2GetIdInfo( 2090 gw_return_object.session, 2091 gw_return_object.issue_id, 2092 ct.byref(gw_return_object.buffer_length), 2093 ct.byref(gw_return_object.buffer) 2094 ) 2095 2096 # Editor wrote to a buffer, convert it to bytes 2097 id_info_bytes = utils.buffer_to_bytes( 2098 gw_return_object.buffer, 2099 gw_return_object.buffer_length 2100 ) 2101 2102 gw_return_object.id_info = id_info_bytes.decode() 2103 2104 return gw_return_object 2105 2106 def get_id_info(self, issue_id: int, raise_unsupported: bool = True): 2107 """ Retrieves the group description for the given Issue ID. e.g. issue_id 96 returns "Document Processing Instances" 2108 2109 Args: 2110 issue_id (int): The issue id. 2111 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2112 2113 Returns: 2114 id_info (str): The group description for the given Issue ID. 2115 """ 2116 # Validate arg types 2117 if not isinstance(issue_id, int): 2118 raise TypeError(issue_id) 2119 2120 with utils.CwdHandler(self.library_path): 2121 with self.new_session() as session: 2122 result = self._GW2GetIdInfo(session, issue_id) 2123 2124 if result.status not in successes.success_codes: 2125 log.error(format_object(result)) 2126 if raise_unsupported: 2127 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2128 else: 2129 log.debug(format_object(result)) 2130 2131 return result.id_info 2132 2133 def _GW2GetAllIdInfo(self, session: int): 2134 """ Retrieves the XML containing all the Issue ID ranges with their group descriptions 2135 2136 Args: 2137 session (int): The session integer. 2138 2139 Returns: 2140 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'analysis_format', 'status', 'all_id_info'. 2141 """ 2142 2143 # API function declaration 2144 self.library.GW2GetAllIdInfo.argtypes = [ 2145 ct.c_size_t, # Session_Handle session 2146 ct.POINTER(ct.c_size_t), # size_t * bufferLength 2147 ct.POINTER(ct.c_void_p) # char ** outputBuffer 2148 ] 2149 2150 # Variable initialisation 2151 # The extracted issue Id information is stored in the analysis report, register an analysis session. 2152 gw_return_object = self._GW2RegisterAnalysisMemory(session) 2153 2154 # API call 2155 gw_return_object.status = self.library.GW2GetAllIdInfo( 2156 gw_return_object.session, 2157 ct.byref(gw_return_object.buffer_length), 2158 ct.byref(gw_return_object.buffer) 2159 ) 2160 2161 # Editor wrote to a buffer, convert it to bytes 2162 all_id_info_bytes = utils.buffer_to_bytes( 2163 gw_return_object.buffer, 2164 gw_return_object.buffer_length 2165 ) 2166 2167 gw_return_object.all_id_info = all_id_info_bytes.decode() 2168 2169 return gw_return_object 2170 2171 def get_all_id_info(self, output_file: Optional[str] = None, raise_unsupported: bool = True) -> str: 2172 """ Retrieves the XML containing all the Issue ID ranges with their group descriptions 2173 2174 Args: 2175 output_file (Optional[str]): The output file path where the analysis file will be written. 2176 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2177 2178 Returns: 2179 all_id_info (str): A string XML analysis report containing all id info. 2180 """ 2181 # Validate arg types 2182 if not isinstance(output_file, (type(None), str)): 2183 raise TypeError(output_file) 2184 if isinstance(output_file, str): 2185 output_file = os.path.abspath(output_file) 2186 2187 with utils.CwdHandler(self.library_path): 2188 with self.new_session() as session: 2189 result = self._GW2GetAllIdInfo(session) 2190 2191 if result.status not in successes.success_codes: 2192 log.error(format_object(result)) 2193 if raise_unsupported: 2194 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2195 else: 2196 log.debug(format_object(result)) 2197 2198 if isinstance(output_file, str): 2199 # GW2GetAllIdInfo is memory only, write to file 2200 # make directories that do not exist 2201 os.makedirs(os.path.dirname(output_file), exist_ok=True) 2202 with open(output_file, "w") as f: 2203 f.write(result.all_id_info) 2204 2205 return result.all_id_info 2206 2207 def _GW2FileSessionStatus(self, session: int): 2208 """ Retrieves the Glasswall Session Status. Also gives a high level indication of the processing that was carried out on the last document processed by the library 2209 2210 Args: 2211 session (int): The session integer. 2212 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2213 2214 Returns: 2215 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'session_status', 'buffer', 'buffer_length', 'status', 'message'. 2216 """ 2217 # API function declaration 2218 self.library.GW2FileSessionStatus.argtypes = [ 2219 ct.c_size_t, # Session_Handle session 2220 ct.POINTER(ct.c_int), # int *glasswallSessionStatus 2221 ct.POINTER(ct.c_void_p), # char **statusMsgBuffer 2222 ct.POINTER(ct.c_size_t) # size_t *statusbufferLength 2223 ] 2224 2225 # Variable initialisation 2226 gw_return_object = glasswall.GwReturnObj() 2227 gw_return_object.session = ct.c_size_t(session) 2228 gw_return_object.session_status = ct.c_int() 2229 gw_return_object.buffer = ct.c_void_p() 2230 gw_return_object.buffer_length = ct.c_size_t() 2231 2232 # API call 2233 gw_return_object.status = self.library.GW2FileSessionStatus( 2234 gw_return_object.session, 2235 ct.byref(gw_return_object.session_status), 2236 ct.byref(gw_return_object.buffer), 2237 ct.byref(gw_return_object.buffer_length) 2238 ) 2239 2240 # Convert session_status to int 2241 gw_return_object.session_status = gw_return_object.session_status.value 2242 2243 # Editor wrote to a buffer, convert it to bytes 2244 message_bytes = utils.buffer_to_bytes( 2245 gw_return_object.buffer, 2246 gw_return_object.buffer_length 2247 ) 2248 gw_return_object.message = message_bytes.decode() 2249 2250 return gw_return_object 2251 2252 def file_session_status_message(self, session: int, raise_unsupported: bool = True) -> str: 2253 """ Retrieves the Glasswall session status message. Gives a high level indication of the processing that was carried out. 2254 2255 Args: 2256 session (int): The session integer. 2257 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2258 2259 Returns: 2260 result.message (str):The file session status message. 2261 """ 2262 # Validate arg types 2263 if not isinstance(session, int): 2264 raise TypeError(session) 2265 2266 result = self._GW2FileSessionStatus(session) 2267 2268 if result.status not in successes.success_codes: 2269 log.error(format_object(result)) 2270 if raise_unsupported: 2271 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2272 else: 2273 log.debug(format_object(result)) 2274 2275 return result.message 2276 2277 def _GW2LicenceDetails(self, session: int): 2278 """ Returns a human readable string containing licence details. 2279 2280 Args: 2281 session (int): The session integer. 2282 2283 Returns: 2284 licence_details (str): A human readable string representing the relevant information contained in the licence. 2285 """ 2286 # API function declaration 2287 self.library.GW2LicenceDetails.argtypes = [ct.c_size_t] 2288 self.library.GW2LicenceDetails.restype = ct.c_char_p 2289 2290 # Variable initialisation 2291 ct_session = ct.c_size_t(session) 2292 2293 # API call 2294 licence_details = self.library.GW2LicenceDetails(ct_session) 2295 2296 # Convert to Python string 2297 licence_details = ct.string_at(licence_details).decode() 2298 2299 return licence_details 2300 2301 def licence_details(self): 2302 """ Returns a string containing details of the licence. 2303 2304 Returns: 2305 result (str): A string containing details of the licence. 2306 """ 2307 with self.new_session() as session: 2308 result = self._GW2LicenceDetails(session) 2309 2310 log.debug(f"\n\tsession: {session}\n\tGW2LicenceDetails: {result}") 2311 2312 return result 2313 2314 def _GW2RegisterExportTextDumpMemory(self, session: int): 2315 """ Registers an export text dump to be written in memory. 2316 2317 Args: 2318 session (int): The session integer. 2319 2320 Returns: 2321 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2322 """ 2323 # API function declaration 2324 self.library.GW2RegisterExportTextDumpMemory.argtypes = [ 2325 ct.c_size_t, # Session_Handle session 2326 ct.POINTER(ct.c_void_p), # char ** exportTextDumpFileBuffer 2327 ct.POINTER(ct.c_size_t) # size_t * exportTextDumpLength 2328 ] 2329 2330 # Variable initialisation 2331 gw_return_object = glasswall.GwReturnObj() 2332 gw_return_object.session = ct.c_size_t(session) 2333 gw_return_object.buffer = ct.c_void_p() 2334 gw_return_object.buffer_length = ct.c_size_t() 2335 2336 # API call 2337 gw_return_object.status = self.library.GW2RegisterExportTextDumpMemory( 2338 gw_return_object.session, 2339 ct.byref(gw_return_object.buffer), 2340 ct.byref(gw_return_object.buffer_length) 2341 ) 2342 2343 return gw_return_object 2344 2345 def _GW2RegisterExportTextDumpFile(self, session: int, output_file: str): 2346 """ Registers an export text dump to be written to file. 2347 2348 Args: 2349 session (int): The session integer. 2350 output_file (str): The file path of the text dump file. 2351 2352 Returns: 2353 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2354 """ 2355 # API function declaration 2356 self.library.GW2RegisterExportTextDumpFile.argtypes = [ 2357 ct.c_size_t, # Session_Handle session 2358 ct.c_char_p # const char * textDumpFilePathName 2359 ] 2360 2361 # Variable initialisation 2362 gw_return_object = glasswall.GwReturnObj() 2363 gw_return_object.session = ct.c_size_t(session) 2364 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 2365 2366 # API call 2367 gw_return_object.status = self.library.GW2RegisterExportTextDumpFile( 2368 gw_return_object.session, 2369 gw_return_object.output_file 2370 ) 2371 2372 return gw_return_object 2373 2374 def _GW2RegisterLicenceFile(self, session: int, input_file: str): 2375 """ Registers a "gwkey.lic" licence from file path. 2376 2377 Args: 2378 session (int): The session integer. 2379 input_file (str): The "gwkey.lic" licence input file path. 2380 2381 Returns: 2382 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 2383 """ 2384 # API function declaration 2385 self.library.GW2RegisterLicenceFile.argtypes = [ 2386 ct.c_size_t, # Session_Handle session 2387 ct.c_char_p, # const char *filename 2388 ] 2389 2390 # Variable initialisation 2391 gw_return_object = glasswall.GwReturnObj() 2392 gw_return_object.session = ct.c_size_t(session) 2393 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 2394 2395 # API call 2396 gw_return_object.status = self.library.GW2RegisterLicenceFile( 2397 gw_return_object.session, 2398 gw_return_object.input_file, 2399 ) 2400 2401 return gw_return_object 2402 2403 def _GW2RegisterLicenceMemory(self, session: int, input_file: bytes): 2404 """ Registers a "gwkey.lic" licence from memory. 2405 2406 Args: 2407 session (int): The session integer. 2408 input_file (bytes): The "gwkey.lic" licence input file. 2409 2410 Returns: 2411 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2412 """ 2413 # API function declaration 2414 self.library.GW2RegisterLicenceMemory.argtypes = [ 2415 ct.c_size_t, # Session_Handle session 2416 ct.c_char_p, # const char *filename 2417 ct.c_size_t, # size_t licenceLength 2418 ] 2419 2420 # Variable initialisation 2421 gw_return_object = glasswall.GwReturnObj() 2422 gw_return_object.session = ct.c_size_t(session) 2423 gw_return_object.buffer = ct.c_char_p(input_file) 2424 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 2425 2426 # API call 2427 gw_return_object.status = self.library.GW2RegisterLicenceMemory( 2428 gw_return_object.session, 2429 gw_return_object.buffer, 2430 gw_return_object.buffer_length 2431 ) 2432 2433 return gw_return_object 2434 2435 def register_licence(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 2436 """ Registers a "gwkey.lic" licence from file path or memory. 2437 2438 Args: 2439 session (int): The session integer. 2440 input_file (Union[str, bytes, bytearray, io.BytesIO]): The "gwkey.lic" licence. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. 2441 2442 Returns: 2443 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 2444 - If input_file is a str file path: 2445 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 2446 2447 - If input_file is a file in memory: 2448 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2449 """ 2450 if isinstance(input_file, str): 2451 if not os.path.isfile(input_file): 2452 raise FileNotFoundError(input_file) 2453 2454 input_file = os.path.abspath(input_file) 2455 2456 result = self._GW2RegisterLicenceFile(session, input_file) 2457 2458 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 2459 # Convert bytearray and io.BytesIO to bytes 2460 input_file = utils.as_bytes(input_file) 2461 2462 result = self._GW2RegisterLicenceMemory(session, input_file) 2463 2464 else: 2465 raise TypeError(input_file) 2466 2467 if result.status not in successes.success_codes: 2468 log.error(format_object(result)) 2469 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2470 else: 2471 log.debug(format_object(result)) 2472 2473 return result
19class Editor(Library): 20 """ A high level Python wrapper for Glasswall Editor / Core2. """ 21 22 def __init__(self, library_path: str, licence: Union[str, bytes, bytearray, io.BytesIO] = None): 23 """ Initialise the Editor instance. 24 25 Args: 26 library_path (str): The file or directory path to the Editor library. 27 licence (str, bytes, bytearray, or io.BytesIO, optional): The licence file content or path. This can be: 28 - A string representing the file path to the licence. 29 - A `bytes` or `bytearray` object containing the licence data. 30 - An `io.BytesIO` object for in-memory licence data. 31 If not specified, it is assumed that the licence file is located in the same directory as the `library_path`. 32 """ 33 super().__init__(library_path) 34 self.library = self.load_library(os.path.abspath(library_path)) 35 self.licence = licence 36 37 # Validate killswitch has not activated 38 self.validate_licence() 39 40 log.info(f"Loaded Glasswall {self.__class__.__name__} version {self.version()} from {self.library_path}") 41 42 def validate_licence(self): 43 """ Validates the licence of the library by checking the licence details. 44 45 Raises: 46 LicenceExpired: If the licence has expired or could not be validated. 47 """ 48 licence_details = self.licence_details() 49 50 bad_details = [ 51 "Unable to Read Licence Key File", 52 "Licence File Missing Required Contents", 53 "Licence Expired", 54 ] 55 56 if any(bad_detail.lower() in licence_details.lower() for bad_detail in bad_details): 57 # bad_details found in licence_details 58 log.error(f"{self.__class__.__name__} licence validation failed. Licence details:\n{licence_details}") 59 raise errors.LicenceExpired(licence_details) 60 else: 61 log.debug(f"{self.__class__.__name__} licence validated successfully. Licence details:\n{licence_details}") 62 63 def version(self): 64 """ Returns the Glasswall library version. 65 66 Returns: 67 version (str): The Glasswall library version. 68 """ 69 # API function declaration 70 self.library.GW2LibVersion.restype = ct.c_char_p 71 72 # API call 73 version = self.library.GW2LibVersion() 74 75 # Convert to Python string 76 version = ct.string_at(version).decode() 77 78 return version 79 80 def open_session(self): 81 """ Open a new Glasswall session. 82 83 Returns: 84 session (int): An incrementing integer repsenting the current session. 85 """ 86 # API call 87 session = self.library.GW2OpenSession() 88 89 log.debug(f"\n\tsession: {session}") 90 91 if self.licence: 92 # Must register licence on each GW2OpenSession if the licence is not in the same directory as the library 93 self.register_licence(session, self.licence) 94 95 return session 96 97 def close_session(self, session: int) -> int: 98 """ Close the Glasswall session. All resources allocated by the session will be destroyed. 99 100 Args: 101 session (int): The session to close. 102 103 Returns: 104 status (int): The status code of the function call. 105 """ 106 if not isinstance(session, int): 107 raise TypeError(session) 108 109 # API function declaration 110 self.library.GW2CloseSession.argtypes = [ct.c_size_t] 111 112 # Variable initialisation 113 ct_session = ct.c_size_t(session) 114 115 # API call 116 status = self.library.GW2CloseSession(ct_session) 117 118 if status not in successes.success_codes: 119 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 120 else: 121 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 122 123 return status 124 125 @contextmanager 126 def new_session(self): 127 """ Context manager. Opens a new session on entry and closes the session on exit. """ 128 try: 129 session = self.open_session() 130 yield session 131 finally: 132 self.close_session(session) 133 134 def run_session(self, session): 135 """ Runs the Glasswall session and begins processing of a file. 136 137 Args: 138 session (int): The session to run. 139 140 Returns: 141 status (int): The status code of the function call. 142 """ 143 # API function declaration 144 self.library.GW2RunSession.argtypes = [ct.c_size_t] 145 146 # Variable initialisation 147 ct_session = ct.c_size_t(session) 148 149 # API call 150 status = self.library.GW2RunSession(ct_session) 151 152 if status not in successes.success_codes: 153 log.error(f"\n\tsession: {session}\n\tstatus: {status}\n\tGW2FileErrorMsg: {self.file_error_message(session)}") 154 else: 155 log.debug(f"\n\tsession: {session}\n\tstatus: {status}\n\tGW2FileErrorMsg: {self.file_error_message(session)}") 156 157 return status 158 159 def determine_file_type(self, input_file: Union[str, bytes, bytearray, io.BytesIO], as_string: bool = False, raise_unsupported: bool = True) -> Union[int, str]: 160 """ Determine the file type of a given input file, either as an integer identifier or a string. 161 162 Args: 163 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file to analyse. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. 164 as_string (bool, optional): Return file type as string, eg: "bmp" instead of: 29. Defaults to False. 165 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 166 167 Returns: 168 file_type (Union[int, str]): The file type. 169 """ 170 if isinstance(input_file, str): 171 if not os.path.isfile(input_file): 172 raise FileNotFoundError(input_file) 173 174 # convert to ct.c_char_p of bytes 175 ct_input_file = ct.c_char_p(input_file.encode("utf-8")) 176 177 # API call 178 file_type = self.library.GW2DetermineFileTypeFromFile(ct_input_file) 179 180 elif isinstance(input_file, (bytes, bytearray, io.BytesIO)): 181 # convert to bytes 182 bytes_input_file = utils.as_bytes(input_file) 183 184 # ctypes conversion 185 ct_buffer = ct.c_char_p(bytes_input_file) 186 ct_buffer_length = ct.c_size_t(len(bytes_input_file)) 187 188 # API call 189 file_type = self.library.GW2DetermineFileTypeFromMemory( 190 ct_buffer, 191 ct_buffer_length 192 ) 193 194 else: 195 raise TypeError(input_file) 196 197 file_type_as_string = dft.file_type_int_to_str(file_type) 198 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 199 200 if not dft.is_success(file_type): 201 log.warning(f"\n\tfile_type: {file_type}\n\tfile_type_as_string: {file_type_as_string}\n\tinput_file: {input_file_repr}") 202 if raise_unsupported: 203 raise dft.int_class_map.get(file_type, dft.errors.UnknownErrorCode)(file_type) 204 else: 205 log.debug(f"\n\tfile_type: {file_type}\n\tfile_type_as_string: {file_type_as_string}\n\tinput_file: {input_file_repr}") 206 207 if as_string: 208 return file_type_as_string 209 210 return file_type 211 212 def _GW2GetPolicySettings(self, session: int, policy_format: int = 0): 213 """ Get current policy settings for the given session. 214 215 Args: 216 session (int): The session integer. 217 policy_format (int): The format of the content management policy. 0=XML. 218 219 Returns: 220 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status', 'policy'. 221 """ 222 # API function declaration 223 self.library.GW2GetPolicySettings.argtypes = [ 224 ct.c_size_t, # Session_Handle session 225 ct.POINTER(ct.c_void_p), # char ** policiesBuffer 226 ct.POINTER(ct.c_size_t), # size_t * policiesLength 227 ct.c_int, # Policy_Format format 228 ] 229 230 # Variable initialisation 231 gw_return_object = glasswall.GwReturnObj() 232 gw_return_object.session = ct.c_size_t(session) 233 gw_return_object.buffer = ct.c_void_p() 234 gw_return_object.buffer_length = ct.c_size_t() 235 gw_return_object.policy_format = ct.c_int(policy_format) 236 237 # API Call 238 gw_return_object.status = self.library.GW2GetPolicySettings( 239 gw_return_object.session, 240 ct.byref(gw_return_object.buffer), 241 ct.byref(gw_return_object.buffer_length), 242 gw_return_object.policy_format 243 ) 244 245 # Editor wrote to a buffer, convert it to bytes 246 policy_bytes = utils.buffer_to_bytes( 247 gw_return_object.buffer, 248 gw_return_object.buffer_length 249 ) 250 251 gw_return_object.policy = policy_bytes.decode() 252 253 return gw_return_object 254 255 def get_content_management_policy(self, session: int): 256 """ Returns the content management configuration for a given session. 257 258 Args: 259 session (int): The session integer. 260 261 Returns: 262 xml_string (str): The XML string of the current content management configuration. 263 """ 264 # NOTE GW2GetPolicySettings is current not implemented in editor 265 266 # set xml_string as loaded default config 267 xml_string = glasswall.content_management.policies.Editor(default="sanitise").text, 268 269 # log.debug(f"xml_string:\n{xml_string}") 270 271 return xml_string 272 273 # # API function declaration 274 # self.library.GW2GetPolicySettings.argtypes = [ 275 # ct.c_size_t, 276 # ct.c_void_p, 277 # ] 278 279 # # Variable initialisation 280 # ct_session = ct.c_size_t(session) 281 # ct_buffer = ct.c_void_p() 282 # ct_buffer_length = ct.c_size_t() 283 # # ct_file_format = ct.c_int(file_format) 284 285 # # API Call 286 # status = self.library.GW2GetPolicySettings( 287 # ct_session, 288 # ct.byref(ct_buffer), 289 # ct.byref(ct_buffer_length) 290 # ) 291 292 # print("GW2GetPolicySettings status:", status) 293 294 # file_bytes = utils.buffer_to_bytes( 295 # ct_buffer, 296 # ct_buffer_length, 297 # ) 298 299 # return file_bytes 300 301 def _GW2RegisterPoliciesFile(self, session: int, input_file: str, policy_format: int = 0): 302 """ Registers the policies to be used by Glasswall when processing files. 303 304 Args: 305 session (int): The session integer. 306 input_file (str): The content management policy input file path. 307 policy_format (int): The format of the content management policy. 0=XML. 308 309 Returns: 310 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'policy_format', 'status'. 311 """ 312 # API function declaration 313 self.library.GW2RegisterPoliciesFile.argtypes = [ 314 ct.c_size_t, # Session_Handle session 315 ct.c_char_p, # const char *filename 316 ct.c_int, # Policy_Format format 317 ] 318 319 # Variable initialisation 320 gw_return_object = glasswall.GwReturnObj() 321 gw_return_object.session = ct.c_size_t(session) 322 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 323 gw_return_object.policy_format = ct.c_int(policy_format) 324 325 gw_return_object.status = self.library.GW2RegisterPoliciesFile( 326 gw_return_object.session, 327 gw_return_object.input_file, 328 gw_return_object.policy_format 329 ) 330 331 return gw_return_object 332 333 def _GW2RegisterPoliciesMemory(self, session: int, input_file: bytes, policy_format: int = 0): 334 """ Registers the policies in memory to be used by Glasswall when processing files. 335 336 Args: 337 session (int): The session integer. 338 input_file (str): The content management policy input file bytes. 339 policy_format (int): The format of the content management policy. 0=XML. 340 341 Returns: 342 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status'. 343 """ 344 # API function declaration 345 self.library.GW2RegisterPoliciesMemory.argtype = [ 346 ct.c_size_t, # Session_Handle session 347 ct.c_char_p, # const char *policies 348 ct.c_size_t, # size_t policiesLength 349 ct.c_int # Policy_Format format 350 ] 351 352 # Variable initialisation 353 gw_return_object = glasswall.GwReturnObj() 354 gw_return_object.session = ct.c_size_t(session) 355 gw_return_object.buffer = ct.c_char_p(input_file) 356 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 357 gw_return_object.policy_format = ct.c_int(policy_format) 358 359 # API Call 360 gw_return_object.status = self.library.GW2RegisterPoliciesMemory( 361 gw_return_object.session, 362 gw_return_object.buffer, 363 gw_return_object.buffer_length, 364 gw_return_object.policy_format 365 ) 366 367 return gw_return_object 368 369 def set_content_management_policy(self, session: int, input_file: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, policy_format=0): 370 """ Sets the content management policy configuration. If input_file is None then default settings (sanitise) are applied. 371 372 Args: 373 session (int): The session integer. 374 input_file (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 375 policy_format (int): The format of the content management policy. 0=XML. 376 377 Returns: 378 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 379 - If input_file is a str file path: 380 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'policy_format', 'status'. 381 382 - If input_file is a file in memory: 383 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status'. 384 """ 385 # Validate type 386 if not isinstance(session, int): 387 raise TypeError(session) 388 if not isinstance(input_file, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 389 raise TypeError(input_file) 390 if not isinstance(policy_format, int): 391 raise TypeError(policy_format) 392 393 # Set input_file to default if input_file is None 394 if input_file is None: 395 input_file = glasswall.content_management.policies.Editor(default="sanitise") 396 397 # Validate xml content is parsable 398 utils.validate_xml(input_file) 399 400 # From file 401 if isinstance(input_file, str) and os.path.isfile(input_file): 402 input_file = os.path.abspath(input_file) 403 404 result = self._GW2RegisterPoliciesFile(session, input_file) 405 406 # From memory 407 elif isinstance(input_file, (str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 408 # Convert bytearray, io.BytesIO to bytes 409 if isinstance(input_file, (bytearray, io.BytesIO)): 410 input_file = utils.as_bytes(input_file) 411 # Convert string xml or Policy to bytes 412 if isinstance(input_file, (str, glasswall.content_management.policies.policy.Policy)): 413 input_file = input_file.encode("utf-8") 414 415 result = self._GW2RegisterPoliciesMemory(session, input_file) 416 417 if result.status not in successes.success_codes: 418 log.error(format_object(result)) 419 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 420 else: 421 log.debug(format_object(result)) 422 423 return result 424 425 def _GW2RegisterInputFile(self, session: int, input_file: str): 426 """ Register an input file for the given session. 427 428 Args: 429 session (int): The session integer. 430 input_file (str): The input file path. 431 432 Returns: 433 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 434 """ 435 # API function declaration 436 self.library.GW2RegisterInputFile.argtypes = [ 437 ct.c_size_t, # Session_Handle session 438 ct.c_char_p # const char * inputFilePath 439 ] 440 441 # Variable initialisation 442 gw_return_object = glasswall.GwReturnObj() 443 gw_return_object.session = ct.c_size_t(session) 444 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 445 gw_return_object.input_file_path = input_file 446 447 # API call 448 gw_return_object.status = self.library.GW2RegisterInputFile( 449 gw_return_object.session, 450 gw_return_object.input_file 451 ) 452 453 return gw_return_object 454 455 def _GW2RegisterInputMemory(self, session: int, input_file: bytes): 456 """ Register an input file in memory for the given session. 457 458 Args: 459 session (int): The session integer. 460 input_file (bytes): The input file in memory. 461 462 Returns: 463 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 464 """ 465 # API function declaration 466 self.library.GW2RegisterInputMemory.argtypes = [ 467 ct.c_size_t, # Session_Handle session 468 ct.c_char_p, # const char * inputFileBuffer 469 ct.c_size_t, # size_t inputLength 470 ] 471 472 # Variable initialisation 473 gw_return_object = glasswall.GwReturnObj() 474 gw_return_object.session = ct.c_size_t(session) 475 gw_return_object.buffer = ct.c_char_p(input_file) 476 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 477 478 # API call 479 gw_return_object.status = self.library.GW2RegisterInputMemory( 480 gw_return_object.session, 481 gw_return_object.buffer, 482 gw_return_object.buffer_length 483 ) 484 485 return gw_return_object 486 487 def register_input(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 488 """ Register an input file or bytes for the given session. 489 490 Args: 491 session (int): The session integer. 492 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 493 494 Returns: 495 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 496 - If input_file is a str file path: 497 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 498 499 - If input_file is a file in memory: 500 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 501 """ 502 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO,)): 503 raise TypeError(input_file) 504 505 if isinstance(input_file, str): 506 if not os.path.isfile(input_file): 507 raise FileNotFoundError(input_file) 508 509 input_file = os.path.abspath(input_file) 510 511 result = self._GW2RegisterInputFile(session, input_file) 512 513 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 514 # Convert bytearray and io.BytesIO to bytes 515 input_file = utils.as_bytes(input_file) 516 517 result = self._GW2RegisterInputMemory(session, input_file) 518 519 if result.status not in successes.success_codes: 520 log.error(format_object(result)) 521 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 522 else: 523 log.debug(format_object(result)) 524 525 return result 526 527 def _GW2RegisterOutFile(self, session: int, output_file: str): 528 """ Register an output file for the given session. 529 530 Args: 531 session (int): The session integer. 532 output_file (str): The output file path. 533 534 Returns: 535 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 536 """ 537 # API function declaration 538 self.library.GW2RegisterOutFile.argtypes = [ 539 ct.c_size_t, # Session_Handle session 540 ct.c_char_p # const char * outputFilePath 541 ] 542 543 # Variable initialisation 544 gw_return_object = glasswall.GwReturnObj() 545 gw_return_object.session = ct.c_size_t(session) 546 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 547 548 # API call 549 gw_return_object.status = self.library.GW2RegisterOutFile( 550 gw_return_object.session, 551 gw_return_object.output_file 552 ) 553 554 return gw_return_object 555 556 def _GW2RegisterOutputMemory(self, session: int): 557 """ Register an output file in memory for the given session. 558 559 Args: 560 session (int): The session integer. 561 562 Returns: 563 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 564 """ 565 # API function declaration 566 self.library.GW2RegisterOutputMemory.argtypes = [ 567 ct.c_size_t, # Session_Handle session 568 ct.POINTER(ct.c_void_p), # char ** outputBuffer 569 ct.POINTER(ct.c_size_t) # size_t * outputLength 570 ] 571 572 # Variable initialisation 573 gw_return_object = glasswall.GwReturnObj() 574 gw_return_object.session = ct.c_size_t(session) 575 gw_return_object.buffer = ct.c_void_p() 576 gw_return_object.buffer_length = ct.c_size_t() 577 578 # API call 579 gw_return_object.status = self.library.GW2RegisterOutputMemory( 580 gw_return_object.session, 581 ct.byref(gw_return_object.buffer), 582 ct.byref(gw_return_object.buffer_length) 583 ) 584 585 return gw_return_object 586 587 def register_output(self, session, output_file: Optional[str] = None): 588 """ Register an output file for the given session. If output_file is None the file will be returned as 'buffer' and 'buffer_length' attributes. 589 590 Args: 591 session (int): The session integer. 592 output_file (Optional[str]): If specified, during run session the file will be written to output_file, otherwise the file will be written to the glasswall.GwReturnObj 'buffer' and 'buffer_length' attributes. 593 594 Returns: 595 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 596 """ 597 if not isinstance(output_file, (type(None), str)): 598 raise TypeError(output_file) 599 600 if isinstance(output_file, str): 601 output_file = os.path.abspath(output_file) 602 603 result = self._GW2RegisterOutFile(session, output_file) 604 605 elif isinstance(output_file, type(None)): 606 result = self._GW2RegisterOutputMemory(session) 607 608 if result.status not in successes.success_codes: 609 log.error(format_object(result)) 610 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 611 else: 612 log.debug(format_object(result)) 613 614 return result 615 616 def _GW2RegisterAnalysisFile(self, session: int, output_file: str, analysis_format: int = 0): 617 """ Register an analysis output file for the given session. 618 619 Args: 620 session (int): The session integer. 621 output_file (str): The analysis output file path. 622 analysis_format (int): The format of the analysis report. 0=XML, 1=XMLExtended 623 624 Returns: 625 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'analysis_format', 'status'. 626 """ 627 # API function declaration 628 self.library.GW2RegisterAnalysisFile.argtypes = [ 629 ct.c_size_t, # Session_Handle session 630 ct.c_char_p, # const char * analysisFilePathName 631 ct.c_int, # Analysis_Format format 632 ] 633 634 # Variable initialisation 635 gw_return_object = glasswall.GwReturnObj() 636 gw_return_object.session = ct.c_size_t(session) 637 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 638 gw_return_object.analysis_format = ct.c_int() 639 640 # API call 641 gw_return_object.status = self.library.GW2RegisterAnalysisFile( 642 gw_return_object.session, 643 gw_return_object.output_file, 644 gw_return_object.analysis_format 645 ) 646 647 return gw_return_object 648 649 def _GW2RegisterAnalysisMemory(self, session: int, analysis_format: int = 0): 650 """ Register an analysis output file in memory for the given session. 651 652 Args: 653 session (int): The session integer. 654 analysis_format (int): The format of the analysis report. 0=XML, 1=XMLExtended 655 656 Returns: 657 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'analysis_format', 'status'. 658 """ 659 # API function declaration 660 self.library.GW2RegisterAnalysisMemory.argtypes = [ 661 ct.c_size_t, # Session_Handle session 662 ct.POINTER(ct.c_void_p), # char ** analysisFileBuffer 663 ct.POINTER(ct.c_size_t), # size_t * analysisoutputLength 664 ct.c_int # Analysis_Format format 665 ] 666 667 # Variable initialisation 668 gw_return_object = glasswall.GwReturnObj() 669 gw_return_object.session = ct.c_size_t(session) 670 gw_return_object.buffer = ct.c_void_p() 671 gw_return_object.buffer_length = ct.c_size_t() 672 gw_return_object.analysis_format = ct.c_int() 673 674 # API call 675 gw_return_object.status = self.library.GW2RegisterAnalysisMemory( 676 gw_return_object.session, 677 ct.byref(gw_return_object.buffer), 678 ct.byref(gw_return_object.buffer_length), 679 gw_return_object.analysis_format 680 ) 681 682 return gw_return_object 683 684 def register_analysis(self, session: int, output_file: Optional[str] = None): 685 """ Registers an analysis file for the given session. The analysis file will be created during the session's run_session call. 686 687 Args: 688 session (int): The session integer. 689 output_file (Optional[str]): Default None. The file path where the analysis will be written. None returns the analysis as bytes. 690 691 Returns: 692 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'status', 'session', 'analysis_format'. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. If output_file is not None (file mode) 'output_file' is included. 693 """ 694 if not isinstance(output_file, (type(None), str)): 695 raise TypeError(output_file) 696 697 if isinstance(output_file, str): 698 output_file = os.path.abspath(output_file) 699 700 result = self._GW2RegisterAnalysisFile(session, output_file) 701 702 elif isinstance(output_file, type(None)): 703 result = self._GW2RegisterAnalysisMemory(session) 704 705 if result.status not in successes.success_codes: 706 log.error(format_object(result)) 707 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 708 else: 709 log.debug(format_object(result)) 710 711 return result 712 713 def protect_file( 714 self, 715 input_file: Union[str, bytes, bytearray, io.BytesIO], 716 output_file: Optional[str] = None, 717 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 718 raise_unsupported: bool = True, 719 ): 720 """ Protects a file using the current content management configuration, returning the file bytes. The protected file is written to output_file if it is provided. 721 722 Args: 723 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 724 output_file (Optional[str]): The output file path where the protected file will be written. 725 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 726 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 727 728 Returns: 729 file_bytes (bytes): The protected file bytes. 730 """ 731 # Validate arg types 732 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 733 raise TypeError(input_file) 734 if not isinstance(output_file, (type(None), str)): 735 raise TypeError(output_file) 736 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 737 raise TypeError(content_management_policy) 738 if not isinstance(raise_unsupported, bool): 739 raise TypeError(raise_unsupported) 740 741 # Convert string path arguments to absolute paths 742 if isinstance(input_file, str): 743 if not os.path.isfile(input_file): 744 raise FileNotFoundError(input_file) 745 input_file = os.path.abspath(input_file) 746 if isinstance(output_file, str): 747 output_file = os.path.abspath(output_file) 748 # make directories that do not exist 749 os.makedirs(os.path.dirname(output_file), exist_ok=True) 750 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 751 content_management_policy = os.path.abspath(content_management_policy) 752 753 # Convert memory inputs to bytes 754 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 755 input_file = utils.as_bytes(input_file) 756 757 with utils.CwdHandler(self.library_path): 758 with self.new_session() as session: 759 content_management_policy = self.set_content_management_policy(session, content_management_policy) 760 register_input = self.register_input(session, input_file) 761 register_output = self.register_output(session, output_file=output_file) 762 status = self.run_session(session) 763 764 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 765 if status not in successes.success_codes: 766 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 767 if raise_unsupported: 768 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 769 else: 770 file_bytes = None 771 else: 772 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 773 # Get file bytes 774 if isinstance(output_file, str): 775 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 776 if not os.path.isfile(output_file): 777 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 778 file_bytes = None 779 else: 780 with open(output_file, "rb") as f: 781 file_bytes = f.read() 782 else: 783 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 784 file_bytes = utils.buffer_to_bytes( 785 register_output.buffer, 786 register_output.buffer_length 787 ) 788 789 # Ensure memory allocated is not garbage collected 790 content_management_policy, register_input, register_output 791 792 return file_bytes 793 794 def protect_directory( 795 self, 796 input_directory: str, 797 output_directory: Optional[str] = None, 798 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 799 raise_unsupported: bool = True, 800 ): 801 """ Recursively processes all files in a directory in protect mode using the given content management policy. 802 The protected files are written to output_directory maintaining the same directory structure as input_directory. 803 804 Args: 805 input_directory (str): The input directory containing files to protect. 806 output_directory (Optional[str]): The output directory where the protected file will be written, or None to not write files. 807 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 808 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 809 810 Returns: 811 protected_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 812 """ 813 protected_files_dict = {} 814 # Call protect_file on each file in input_directory to output_directory 815 for input_file in utils.list_file_paths(input_directory): 816 relative_path = os.path.relpath(input_file, input_directory) 817 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 818 819 protected_bytes = self.protect_file( 820 input_file=input_file, 821 output_file=output_file, 822 raise_unsupported=raise_unsupported, 823 content_management_policy=content_management_policy, 824 ) 825 826 protected_files_dict[relative_path] = protected_bytes 827 828 return protected_files_dict 829 830 def analyse_file( 831 self, 832 input_file: Union[str, bytes, bytearray, io.BytesIO], 833 output_file: Optional[str] = None, 834 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 835 raise_unsupported: bool = True, 836 ): 837 """ Analyses a file, returning the analysis bytes. The analysis is written to output_file if it is provided. 838 839 Args: 840 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 841 output_file (Optional[str]): The output file path where the analysis file will be written. 842 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 843 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 844 845 Returns: 846 file_bytes (bytes): The analysis file bytes. 847 """ 848 # Validate arg types 849 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 850 raise TypeError(input_file) 851 if not isinstance(output_file, (type(None), str)): 852 raise TypeError(output_file) 853 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 854 raise TypeError(content_management_policy) 855 if not isinstance(raise_unsupported, bool): 856 raise TypeError(raise_unsupported) 857 858 # Convert string path arguments to absolute paths 859 if isinstance(input_file, str): 860 if not os.path.isfile(input_file): 861 raise FileNotFoundError(input_file) 862 input_file = os.path.abspath(input_file) 863 if isinstance(output_file, str): 864 output_file = os.path.abspath(output_file) 865 # make directories that do not exist 866 os.makedirs(os.path.dirname(output_file), exist_ok=True) 867 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 868 content_management_policy = os.path.abspath(content_management_policy) 869 870 # Convert memory inputs to bytes 871 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 872 input_file = utils.as_bytes(input_file) 873 874 with utils.CwdHandler(self.library_path): 875 with self.new_session() as session: 876 content_management_policy = self.set_content_management_policy(session, content_management_policy) 877 register_input = self.register_input(session, input_file) 878 register_analysis = self.register_analysis(session, output_file) 879 status = self.run_session(session) 880 881 file_bytes = None 882 if isinstance(output_file, str): 883 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 884 if os.path.isfile(output_file): 885 with open(output_file, "rb") as f: 886 file_bytes = f.read() 887 else: 888 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 889 if register_analysis.buffer and register_analysis.buffer_length: 890 file_bytes = utils.buffer_to_bytes( 891 register_analysis.buffer, 892 register_analysis.buffer_length 893 ) 894 895 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 896 if status not in successes.success_codes: 897 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 898 if raise_unsupported: 899 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 900 else: 901 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 902 903 # Ensure memory allocated is not garbage collected 904 content_management_policy, register_input, register_analysis 905 906 return file_bytes 907 908 def analyse_directory( 909 self, 910 input_directory: str, 911 output_directory: Optional[str] = None, 912 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 913 raise_unsupported: bool = True, 914 ): 915 """ Analyses all files in a directory and its subdirectories. The analysis files are written to output_directory maintaining the same directory structure as input_directory. 916 917 Args: 918 input_directory (str): The input directory containing files to analyse. 919 output_directory (Optional[str]): The output directory where the analysis files will be written, or None to not write files. 920 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 921 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 922 923 Returns: 924 analysis_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 925 """ 926 analysis_files_dict = {} 927 # Call analyse_file on each file in input_directory to output_directory 928 for input_file in utils.list_file_paths(input_directory): 929 relative_path = os.path.relpath(input_file, input_directory) + ".xml" 930 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 931 932 analysis_bytes = self.analyse_file( 933 input_file=input_file, 934 output_file=output_file, 935 raise_unsupported=raise_unsupported, 936 content_management_policy=content_management_policy, 937 ) 938 939 analysis_files_dict[relative_path] = analysis_bytes 940 941 return analysis_files_dict 942 943 def protect_and_analyse_file( 944 self, 945 input_file: Union[str, bytes, bytearray, io.BytesIO], 946 output_file: Optional[str] = None, 947 output_analysis_report: Optional[str] = None, 948 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 949 raise_unsupported: bool = True, 950 ): 951 """ Protects and analyses a file in a single session, returning both protected file bytes and analysis report bytes. 952 953 Args: 954 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 955 output_file (Optional[str]): The output file path where the protected file will be written. 956 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 957 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 958 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 959 960 Returns: 961 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (protected_file_bytes, analysis_report_bytes). 962 """ 963 # Validate arg types 964 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 965 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 966 if not isinstance(output_file, (type(None), str)): 967 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 968 if not isinstance(output_analysis_report, (type(None), str)): 969 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 970 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 971 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 972 if not isinstance(raise_unsupported, bool): 973 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 974 975 # Convert string path arguments to absolute paths 976 if isinstance(input_file, str): 977 if not os.path.isfile(input_file): 978 raise FileNotFoundError(input_file) 979 input_file = os.path.abspath(input_file) 980 if isinstance(output_file, str): 981 output_file = os.path.abspath(output_file) 982 os.makedirs(os.path.dirname(output_file), exist_ok=True) 983 if isinstance(output_analysis_report, str): 984 output_analysis_report = os.path.abspath(output_analysis_report) 985 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 986 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 987 content_management_policy = os.path.abspath(content_management_policy) 988 989 # Convert memory inputs to bytes 990 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 991 input_file = utils.as_bytes(input_file) 992 993 with utils.CwdHandler(self.library_path): 994 with self.new_session() as session: 995 content_management_policy = self.set_content_management_policy(session, content_management_policy) 996 register_input = self.register_input(session, input_file) 997 register_output = self.register_output(session, output_file) 998 register_analysis = self.register_analysis(session, output_analysis_report) 999 1000 status = self.run_session(session) 1001 1002 protected_file_bytes = None 1003 analysis_report_bytes = None 1004 1005 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1006 if status not in successes.success_codes: 1007 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1008 if raise_unsupported: 1009 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1010 1011 # Get analysis report file bytes, even on processing failure 1012 if isinstance(output_analysis_report, str): 1013 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1014 if not os.path.isfile(output_analysis_report): 1015 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1016 else: 1017 with open(output_analysis_report, "rb") as f: 1018 analysis_report_bytes = f.read() 1019 else: 1020 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1021 if register_analysis.buffer and register_analysis.buffer_length: 1022 analysis_report_bytes = utils.buffer_to_bytes( 1023 register_analysis.buffer, 1024 register_analysis.buffer_length 1025 ) 1026 1027 # On success, get protected file bytes 1028 if status in successes.success_codes: 1029 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1030 # Get file bytes 1031 if isinstance(output_file, str): 1032 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1033 if not os.path.isfile(output_file): 1034 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1035 else: 1036 with open(output_file, "rb") as f: 1037 protected_file_bytes = f.read() 1038 else: 1039 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1040 protected_file_bytes = utils.buffer_to_bytes( 1041 register_output.buffer, 1042 register_output.buffer_length 1043 ) 1044 1045 # Ensure memory allocated is not garbage collected 1046 content_management_policy, register_input, register_output, register_analysis 1047 1048 return protected_file_bytes, analysis_report_bytes 1049 1050 def protect_and_analyse_directory( 1051 self, 1052 input_directory: str, 1053 output_directory: Optional[str] = None, 1054 analysis_directory: Optional[str] = None, 1055 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1056 raise_unsupported: bool = True, 1057 ): 1058 """ Recursively processes all files in a directory using protect and analyse mode with the given content management policy. 1059 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1060 1061 Args: 1062 input_directory (str): The input directory containing files to process. 1063 output_directory (Optional[str]): The output directory for protected files. 1064 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1065 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1066 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1067 1068 Returns: 1069 result_dict (dict): A dictionary mapping relative file paths to tuples of (protected_file_bytes, analysis_report_bytes). 1070 """ 1071 result_dict = {} 1072 for input_file in utils.list_file_paths(input_directory): 1073 relative_path = os.path.relpath(input_file, input_directory) 1074 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1075 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1076 1077 protected_file_bytes, analysis_report_bytes = self.protect_and_analyse_file( 1078 input_file=input_file, 1079 output_file=output_file, 1080 output_analysis_report=output_analysis_report, 1081 content_management_policy=content_management_policy, 1082 raise_unsupported=raise_unsupported, 1083 ) 1084 1085 result_dict[relative_path] = (protected_file_bytes, analysis_report_bytes) 1086 1087 return result_dict 1088 1089 def _GW2RegisterExportFile(self, session: int, output_file: str): 1090 """ Register an export output file for the given session. 1091 1092 Args: 1093 session (int): The session integer. 1094 output_file (str): The export output file path. 1095 1096 Returns: 1097 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 1098 """ 1099 # API function declaration 1100 self.library.GW2RegisterExportFile.argtypes = [ 1101 ct.c_size_t, # Session_Handle session 1102 ct.c_char_p # const char * exportFilePath 1103 ] 1104 1105 # Variable initialisation 1106 gw_return_object = glasswall.GwReturnObj() 1107 gw_return_object.session = ct.c_size_t(session) 1108 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 1109 1110 # API Call 1111 gw_return_object.status = self.library.GW2RegisterExportFile( 1112 gw_return_object.session, 1113 gw_return_object.output_file 1114 ) 1115 1116 return gw_return_object 1117 1118 def _GW2RegisterExportMemory(self, session: int): 1119 """ Register an export output file in memory for the given session. 1120 1121 Args: 1122 session (int): The session integer. 1123 1124 Returns: 1125 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 1126 """ 1127 # API function declaration 1128 self.library.GW2RegisterExportMemory.argtypes = [ 1129 ct.c_size_t, # Session_Handle session 1130 ct.POINTER(ct.c_void_p), # char ** exportFileBuffer 1131 ct.POINTER(ct.c_size_t) # size_t * exportLength 1132 ] 1133 1134 # Variable initialisation 1135 gw_return_object = glasswall.GwReturnObj() 1136 gw_return_object.session = ct.c_size_t(session) 1137 gw_return_object.buffer = ct.c_void_p() 1138 gw_return_object.buffer_length = ct.c_size_t() 1139 1140 # API call 1141 gw_return_object.status = self.library.GW2RegisterExportMemory( 1142 gw_return_object.session, 1143 ct.byref(gw_return_object.buffer), 1144 ct.byref(gw_return_object.buffer_length) 1145 ) 1146 1147 return gw_return_object 1148 1149 def register_export(self, session: int, output_file: Optional[str] = None): 1150 """ Registers a file to be exported for the given session. The export file will be created during the session's run_session call. 1151 1152 Args: 1153 session (int): The session integer. 1154 output_file (Optional[str]): Default None. The file path where the export will be written. None exports the file in memory. 1155 1156 Returns: 1157 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call and 'session', the session integer. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 1158 """ 1159 if not isinstance(output_file, (type(None), str)): 1160 raise TypeError(output_file) 1161 1162 if isinstance(output_file, str): 1163 output_file = os.path.abspath(output_file) 1164 1165 result = self._GW2RegisterExportFile(session, output_file) 1166 1167 elif isinstance(output_file, type(None)): 1168 result = self._GW2RegisterExportMemory(session) 1169 1170 if result.status not in successes.success_codes: 1171 log.error(format_object(result)) 1172 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1173 else: 1174 log.debug(format_object(result)) 1175 1176 return result 1177 1178 def export_file( 1179 self, 1180 input_file: Union[str, bytes, bytearray, io.BytesIO], 1181 output_file: Optional[str] = None, 1182 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1183 raise_unsupported: bool = True, 1184 ): 1185 """ Export a file, returning the .zip file bytes. The .zip file is written to output_file if it is provided. 1186 1187 Args: 1188 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1189 output_file (Optional[str]): The output file path where the .zip file will be written. 1190 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1191 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1192 1193 Returns: 1194 file_bytes (bytes): The exported .zip file. 1195 """ 1196 # Validate arg types 1197 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1198 raise TypeError(input_file) 1199 if not isinstance(output_file, (type(None), str)): 1200 raise TypeError(output_file) 1201 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1202 raise TypeError(content_management_policy) 1203 if not isinstance(raise_unsupported, bool): 1204 raise TypeError(raise_unsupported) 1205 1206 # Convert string path arguments to absolute paths 1207 if isinstance(input_file, str): 1208 if not os.path.isfile(input_file): 1209 raise FileNotFoundError(input_file) 1210 input_file = os.path.abspath(input_file) 1211 if isinstance(output_file, str): 1212 output_file = os.path.abspath(output_file) 1213 # make directories that do not exist 1214 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1215 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1216 content_management_policy = os.path.abspath(content_management_policy) 1217 1218 # Convert memory inputs to bytes 1219 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1220 input_file = utils.as_bytes(input_file) 1221 1222 with utils.CwdHandler(self.library_path): 1223 with self.new_session() as session: 1224 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1225 register_input = self.register_input(session, input_file) 1226 register_export = self.register_export(session, output_file) 1227 status = self.run_session(session) 1228 1229 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1230 if status not in successes.success_codes: 1231 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1232 if raise_unsupported: 1233 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1234 else: 1235 file_bytes = None 1236 else: 1237 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1238 # Get file bytes 1239 if isinstance(output_file, str): 1240 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1241 if not os.path.isfile(output_file): 1242 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1243 file_bytes = None 1244 else: 1245 with open(output_file, "rb") as f: 1246 file_bytes = f.read() 1247 else: 1248 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1249 file_bytes = utils.buffer_to_bytes( 1250 register_export.buffer, 1251 register_export.buffer_length 1252 ) 1253 1254 # Ensure memory allocated is not garbage collected 1255 content_management_policy, register_input, register_export 1256 1257 return file_bytes 1258 1259 def export_directory( 1260 self, 1261 input_directory: str, 1262 output_directory: Optional[str] = None, 1263 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1264 raise_unsupported: bool = True 1265 ): 1266 """ Exports all files in a directory and its subdirectories. The export files are written to output_directory maintaining the same directory structure as input_directory. 1267 1268 Args: 1269 input_directory (str): The input directory containing files to export. 1270 output_directory (Optional[str]): The output directory where the export files will be written, or None to not write files. 1271 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 1272 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1273 1274 Returns: 1275 export_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 1276 """ 1277 export_files_dict = {} 1278 # Call export_file on each file in input_directory to output_directory 1279 for input_file in utils.list_file_paths(input_directory): 1280 relative_path = os.path.relpath(input_file, input_directory) + ".zip" 1281 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1282 1283 export_bytes = self.export_file( 1284 input_file=input_file, 1285 output_file=output_file, 1286 raise_unsupported=raise_unsupported, 1287 content_management_policy=content_management_policy, 1288 ) 1289 1290 export_files_dict[relative_path] = export_bytes 1291 1292 return export_files_dict 1293 1294 def export_and_analyse_file( 1295 self, 1296 input_file: Union[str, bytes, bytearray, io.BytesIO], 1297 output_file: Optional[str] = None, 1298 output_analysis_report: Optional[str] = None, 1299 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1300 raise_unsupported: bool = True, 1301 ): 1302 """ Exports and analyses a file in a single session, returning both exported .zip bytes and analysis report bytes. 1303 1304 Args: 1305 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1306 output_file (Optional[str]): The output file path where the .zip export will be written. 1307 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 1308 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1309 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1310 1311 Returns: 1312 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (export_file_bytes, analysis_report_bytes). 1313 """ 1314 # Validate arg types 1315 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1316 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 1317 if not isinstance(output_file, (type(None), str)): 1318 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 1319 if not isinstance(output_analysis_report, (type(None), str)): 1320 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 1321 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1322 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 1323 if not isinstance(raise_unsupported, bool): 1324 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 1325 1326 # Convert string path arguments to absolute paths 1327 if isinstance(input_file, str): 1328 if not os.path.isfile(input_file): 1329 raise FileNotFoundError(input_file) 1330 input_file = os.path.abspath(input_file) 1331 if isinstance(output_file, str): 1332 output_file = os.path.abspath(output_file) 1333 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1334 if isinstance(output_analysis_report, str): 1335 output_analysis_report = os.path.abspath(output_analysis_report) 1336 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 1337 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1338 content_management_policy = os.path.abspath(content_management_policy) 1339 1340 # Convert memory inputs to bytes 1341 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1342 input_file = utils.as_bytes(input_file) 1343 1344 with utils.CwdHandler(self.library_path): 1345 with self.new_session() as session: 1346 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1347 register_input = self.register_input(session, input_file) 1348 register_export = self.register_export(session, output_file) 1349 register_analysis = self.register_analysis(session, output_analysis_report) 1350 1351 status = self.run_session(session) 1352 1353 export_file_bytes = None 1354 analysis_report_bytes = None 1355 1356 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1357 if status not in successes.success_codes: 1358 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1359 if raise_unsupported: 1360 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1361 1362 # Get analysis report file bytes, even on processing failure 1363 if isinstance(output_analysis_report, str): 1364 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1365 if not os.path.isfile(output_analysis_report): 1366 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1367 else: 1368 with open(output_analysis_report, "rb") as f: 1369 analysis_report_bytes = f.read() 1370 else: 1371 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1372 if register_analysis.buffer and register_analysis.buffer_length: 1373 analysis_report_bytes = utils.buffer_to_bytes( 1374 register_analysis.buffer, 1375 register_analysis.buffer_length 1376 ) 1377 1378 # On success, get export file bytes 1379 if status in successes.success_codes: 1380 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1381 # Get export file bytes 1382 if isinstance(output_file, str): 1383 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1384 if not os.path.isfile(output_file): 1385 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1386 else: 1387 with open(output_file, "rb") as f: 1388 export_file_bytes = f.read() 1389 else: 1390 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1391 export_file_bytes = utils.buffer_to_bytes( 1392 register_export.buffer, 1393 register_export.buffer_length 1394 ) 1395 1396 # Ensure memory allocated is not garbage collected 1397 content_management_policy, register_input, register_export, register_analysis 1398 1399 return export_file_bytes, analysis_report_bytes 1400 1401 def export_and_analyse_directory( 1402 self, 1403 input_directory: str, 1404 output_directory: Optional[str] = None, 1405 analysis_directory: Optional[str] = None, 1406 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1407 raise_unsupported: bool = True, 1408 ): 1409 """ Recursively processes all files in a directory using export and analyse mode with the given content management policy. 1410 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1411 1412 Args: 1413 input_directory (str): The input directory containing files to process. 1414 output_directory (Optional[str]): The output directory for exported .zip files. 1415 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1416 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1417 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1418 1419 Returns: 1420 result_dict (dict): A dictionary mapping relative file paths to tuples of (export_file_bytes, analysis_report_bytes). 1421 """ 1422 result_dict = {} 1423 1424 for input_file in utils.list_file_paths(input_directory): 1425 relative_path = os.path.relpath(input_file, input_directory) 1426 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path + ".zip") 1427 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1428 1429 export_file_bytes, analysis_report_bytes = self.export_and_analyse_file( 1430 input_file=input_file, 1431 output_file=output_file, 1432 output_analysis_report=output_analysis_report, 1433 content_management_policy=content_management_policy, 1434 raise_unsupported=raise_unsupported, 1435 ) 1436 1437 result_dict[relative_path] = (export_file_bytes, analysis_report_bytes) 1438 1439 return result_dict 1440 1441 def _GW2RegisterImportFile(self, session: int, input_file: str): 1442 """ Register an import input file for the given session. 1443 1444 Args: 1445 session (int): The session integer. 1446 input_file (str): The input import file path. 1447 1448 Returns: 1449 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 1450 """ 1451 # API function declaration 1452 self.library.GW2RegisterImportFile.argtypes = [ 1453 ct.c_size_t, # Session_Handle session 1454 ct.c_char_p # const char * importFilePath 1455 ] 1456 1457 # Variable initialisation 1458 gw_return_object = glasswall.GwReturnObj() 1459 gw_return_object.session = ct.c_size_t(session) 1460 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 1461 1462 # API Call 1463 gw_return_object.status = self.library.GW2RegisterImportFile( 1464 gw_return_object.session, 1465 gw_return_object.input_file 1466 ) 1467 1468 return gw_return_object 1469 1470 def _GW2RegisterImportMemory(self, session: int, input_file: bytes): 1471 """ Register an import input file in memory for the given session. 1472 1473 Args: 1474 session (int): The session integer. 1475 input_file (str): The input import file in memory. 1476 1477 Returns: 1478 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 1479 """ 1480 # API function declaration 1481 self.library.GW2RegisterImportMemory.argtypes = [ 1482 ct.c_size_t, # Session_Handle session 1483 ct.c_void_p, # char * importFileBuffer 1484 ct.c_size_t # size_t importLength 1485 ] 1486 1487 # Variable initialisation 1488 gw_return_object = glasswall.GwReturnObj() 1489 gw_return_object.session = ct.c_size_t(session) 1490 gw_return_object.buffer = ct.c_char_p(input_file) 1491 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 1492 1493 # API call 1494 gw_return_object.status = self.library.GW2RegisterImportMemory( 1495 gw_return_object.session, 1496 gw_return_object.buffer, 1497 gw_return_object.buffer_length 1498 ) 1499 1500 return gw_return_object 1501 1502 def register_import(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 1503 """ Registers a .zip file to be imported for the given session. The constructed file will be created during the session's run_session call. 1504 1505 Args: 1506 session (int): The session integer. 1507 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input import file path or bytes. 1508 1509 Returns: 1510 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 1511 """ 1512 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO,)): 1513 raise TypeError(input_file) 1514 1515 if isinstance(input_file, str): 1516 if not os.path.isfile(input_file): 1517 raise FileNotFoundError(input_file) 1518 1519 input_file = os.path.abspath(input_file) 1520 1521 result = self._GW2RegisterImportFile(session, input_file) 1522 1523 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 1524 # Convert bytearray and io.BytesIO to bytes 1525 input_file = utils.as_bytes(input_file) 1526 1527 result = self._GW2RegisterImportMemory(session, input_file) 1528 1529 if result.status not in successes.success_codes: 1530 log.error(format_object(result)) 1531 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1532 else: 1533 log.debug(format_object(result)) 1534 1535 return result 1536 1537 def import_file( 1538 self, 1539 input_file: Union[str, bytes, bytearray, io.BytesIO], 1540 output_file: Optional[str] = None, 1541 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1542 raise_unsupported: bool = True, 1543 ): 1544 """ Import a .zip file, constructs a file from the .zip file and returns the file bytes. The file is written to output_file if it is provided. 1545 1546 Args: 1547 input_file (Union[str, bytes, bytearray, io.BytesIO]): The .zip input file path or bytes. 1548 output_file (Optional[str]): The output file path where the constructed file will be written. 1549 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1550 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1551 1552 Returns: 1553 file_bytes (bytes): The imported file bytes. 1554 """ 1555 # Validate arg types 1556 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1557 raise TypeError(input_file) 1558 if not isinstance(output_file, (type(None), str)): 1559 raise TypeError(output_file) 1560 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1561 raise TypeError(content_management_policy) 1562 if not isinstance(raise_unsupported, bool): 1563 raise TypeError(raise_unsupported) 1564 1565 # Convert string path arguments to absolute paths 1566 if isinstance(input_file, str): 1567 if not os.path.isfile(input_file): 1568 raise FileNotFoundError(input_file) 1569 input_file = os.path.abspath(input_file) 1570 if isinstance(output_file, str): 1571 output_file = os.path.abspath(output_file) 1572 # make directories that do not exist 1573 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1574 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1575 content_management_policy = os.path.abspath(content_management_policy) 1576 1577 # Convert memory inputs to bytes 1578 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1579 input_file = utils.as_bytes(input_file) 1580 1581 with utils.CwdHandler(self.library_path): 1582 with self.new_session() as session: 1583 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1584 register_import = self.register_import(session, input_file) 1585 register_output = self.register_output(session, output_file) 1586 status = self.run_session(session) 1587 1588 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1589 if status not in successes.success_codes: 1590 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1591 if raise_unsupported: 1592 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1593 else: 1594 file_bytes = None 1595 else: 1596 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1597 # Get file bytes 1598 if isinstance(output_file, str): 1599 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1600 if not os.path.isfile(output_file): 1601 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1602 file_bytes = None 1603 else: 1604 with open(output_file, "rb") as f: 1605 file_bytes = f.read() 1606 else: 1607 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1608 file_bytes = utils.buffer_to_bytes( 1609 register_output.buffer, 1610 register_output.buffer_length 1611 ) 1612 1613 # Ensure memory allocated is not garbage collected 1614 content_management_policy, register_import, register_output 1615 1616 return file_bytes 1617 1618 def import_directory( 1619 self, 1620 input_directory: str, 1621 output_directory: Optional[str] = None, 1622 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1623 raise_unsupported: bool = True, 1624 ): 1625 """ Imports all files in a directory and its subdirectories. Files are expected as .zip but this is not forced. 1626 The constructed files are written to output_directory maintaining the same directory structure as input_directory. 1627 1628 Args: 1629 input_directory (str): The input directory containing files to import. 1630 output_directory (Optional[str]): The output directory where the constructed files will be written, or None to not write files. 1631 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 1632 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1633 1634 Returns: 1635 import_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 1636 """ 1637 import_files_dict = {} 1638 # Call import_file on each file in input_directory to output_directory 1639 for input_file in utils.list_file_paths(input_directory): 1640 relative_path = os.path.relpath(input_file, input_directory) 1641 # Remove .zip extension from relative_path 1642 if relative_path.endswith(".zip"): 1643 relative_path = os.path.splitext(relative_path)[0] 1644 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1645 1646 import_bytes = self.import_file( 1647 input_file=input_file, 1648 output_file=output_file, 1649 raise_unsupported=raise_unsupported, 1650 content_management_policy=content_management_policy, 1651 ) 1652 1653 import_files_dict[relative_path] = import_bytes 1654 1655 return import_files_dict 1656 1657 def import_and_analyse_file( 1658 self, 1659 input_file: Union[str, bytes, bytearray, io.BytesIO], 1660 output_file: Optional[str] = None, 1661 output_analysis_report: Optional[str] = None, 1662 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1663 raise_unsupported: bool = True, 1664 ): 1665 """ Imports and analyses a file in a single session, returning both imported file bytes and analysis report bytes. 1666 1667 Args: 1668 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1669 output_file (Optional[str]): The output file path where the imported file will be written. 1670 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 1671 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1672 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1673 1674 Returns: 1675 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (import_file_bytes, analysis_report_bytes). 1676 """ 1677 # Validate arg types 1678 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1679 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 1680 if not isinstance(output_file, (type(None), str)): 1681 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 1682 if not isinstance(output_analysis_report, (type(None), str)): 1683 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 1684 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1685 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 1686 if not isinstance(raise_unsupported, bool): 1687 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 1688 1689 # Convert string path arguments to absolute paths 1690 if isinstance(input_file, str): 1691 if not os.path.isfile(input_file): 1692 raise FileNotFoundError(input_file) 1693 input_file = os.path.abspath(input_file) 1694 if isinstance(output_file, str): 1695 output_file = os.path.abspath(output_file) 1696 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1697 if isinstance(output_analysis_report, str): 1698 output_analysis_report = os.path.abspath(output_analysis_report) 1699 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 1700 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1701 content_management_policy = os.path.abspath(content_management_policy) 1702 1703 # Convert memory inputs to bytes 1704 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1705 input_file = utils.as_bytes(input_file) 1706 1707 with utils.CwdHandler(self.library_path): 1708 with self.new_session() as session: 1709 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1710 register_import = self.register_import(session, input_file) 1711 register_output = self.register_output(session, output_file) 1712 register_analysis = self.register_analysis(session, output_analysis_report) 1713 1714 status = self.run_session(session) 1715 1716 import_file_bytes = None 1717 analysis_report_bytes = None 1718 1719 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1720 if status not in successes.success_codes: 1721 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1722 if raise_unsupported: 1723 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1724 1725 # Get analysis report file bytes, even on processing failure 1726 if isinstance(output_analysis_report, str): 1727 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1728 if not os.path.isfile(output_analysis_report): 1729 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1730 else: 1731 with open(output_analysis_report, "rb") as f: 1732 analysis_report_bytes = f.read() 1733 else: 1734 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1735 if register_analysis.buffer and register_analysis.buffer_length: 1736 analysis_report_bytes = utils.buffer_to_bytes( 1737 register_analysis.buffer, 1738 register_analysis.buffer_length 1739 ) 1740 1741 # On success, get import file bytes 1742 if status in successes.success_codes: 1743 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1744 # Get import file bytes 1745 if isinstance(output_file, str): 1746 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1747 if not os.path.isfile(output_file): 1748 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1749 else: 1750 with open(output_file, "rb") as f: 1751 import_file_bytes = f.read() 1752 else: 1753 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1754 import_file_bytes = utils.buffer_to_bytes( 1755 register_import.buffer, 1756 register_import.buffer_length 1757 ) 1758 1759 # Ensure memory allocated is not garbage collected 1760 content_management_policy, register_import, register_output, register_analysis 1761 1762 return import_file_bytes, analysis_report_bytes 1763 1764 def import_and_analyse_directory( 1765 self, 1766 input_directory: str, 1767 output_directory: Optional[str] = None, 1768 analysis_directory: Optional[str] = None, 1769 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1770 raise_unsupported: bool = True, 1771 ): 1772 """ Recursively processes all files in a directory using import and analyse mode with the given content management policy. 1773 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1774 1775 Args: 1776 input_directory (str): The input directory containing export .zip files to process. 1777 output_directory (Optional[str]): The output directory for imported files. 1778 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1779 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1780 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1781 1782 Returns: 1783 result_dict (dict): A dictionary mapping relative file paths to tuples of (import_file_bytes, analysis_report_bytes). 1784 """ 1785 result_dict = {} 1786 1787 for input_file in utils.list_file_paths(input_directory): 1788 relative_path = os.path.relpath(input_file, input_directory) 1789 # Remove .zip extension from relative_path 1790 if relative_path.endswith(".zip"): 1791 relative_path = os.path.splitext(relative_path)[0] 1792 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1793 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1794 1795 import_file_bytes, analysis_report_bytes = self.import_and_analyse_file( 1796 input_file=input_file, 1797 output_file=output_file, 1798 output_analysis_report=output_analysis_report, 1799 content_management_policy=content_management_policy, 1800 raise_unsupported=raise_unsupported, 1801 ) 1802 1803 result_dict[relative_path] = (import_file_bytes, analysis_report_bytes) 1804 1805 return result_dict 1806 1807 def _GW2FileErrorMsg(self, session: int): 1808 """ Retrieve the Glasswall Session Process error message. 1809 1810 Args: 1811 session (int): The session integer. 1812 1813 Returns: 1814 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status', 'error_message'. 1815 """ 1816 # API function declaration 1817 self.library.GW2FileErrorMsg.argtypes = [ 1818 ct.c_size_t, # Session_Handle session 1819 ct.POINTER(ct.c_void_p), # char **errorMsgBuffer 1820 ct.POINTER(ct.c_size_t) # size_t *errorMsgBufferLength 1821 ] 1822 1823 # Variable initialisation 1824 gw_return_object = glasswall.GwReturnObj() 1825 gw_return_object.session = ct.c_size_t(session) 1826 gw_return_object.buffer = ct.c_void_p() 1827 gw_return_object.buffer_length = ct.c_size_t() 1828 1829 # API call 1830 gw_return_object.status = self.library.GW2FileErrorMsg( 1831 gw_return_object.session, 1832 ct.byref(gw_return_object.buffer), 1833 ct.byref(gw_return_object.buffer_length) 1834 ) 1835 1836 # Editor wrote to a buffer, convert it to bytes 1837 error_bytes = utils.buffer_to_bytes( 1838 gw_return_object.buffer, 1839 gw_return_object.buffer_length 1840 ) 1841 1842 gw_return_object.error_message = error_bytes.decode() 1843 1844 return gw_return_object 1845 1846 @functools.lru_cache() 1847 def file_error_message(self, session: int) -> str: 1848 """ Retrieve the Glasswall Session Process error message. 1849 1850 Args: 1851 session (int): The session integer. 1852 1853 Returns: 1854 error_message (str): The Glasswall Session Process error message. 1855 """ 1856 # Validate arg types 1857 if not isinstance(session, int): 1858 raise TypeError(session) 1859 1860 result = self._GW2FileErrorMsg(session) 1861 1862 if result.status not in successes.success_codes: 1863 log.error(format_object(result)) 1864 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1865 else: 1866 log.debug(format_object(result)) 1867 1868 return result.error_message 1869 1870 def GW2GetFileType(self, session: int, file_type_id): 1871 """ Retrieve the file type as a string. 1872 1873 Args: 1874 session (int): The session integer. 1875 file_type_id (int): The file type id. 1876 1877 Returns: 1878 file_type (str): The formal file name for the corresponding file id. 1879 """ 1880 # Validate arg types 1881 if not isinstance(session, int): 1882 raise TypeError(session) 1883 1884 # API function declaration 1885 self.library.GW2GetFileType.argtypes = [ 1886 ct.c_size_t, 1887 ct.c_size_t, 1888 ct.POINTER(ct.c_size_t), 1889 ct.POINTER(ct.c_void_p) 1890 ] 1891 1892 # Variable initialisation 1893 ct_session = ct.c_size_t(session) 1894 ct_file_type = ct.c_size_t(file_type_id) 1895 ct_buffer_length = ct.c_size_t() 1896 ct_buffer = ct.c_void_p() 1897 1898 # API call 1899 status = self.library.GW2GetFileType( 1900 ct_session, 1901 ct_file_type, 1902 ct.byref(ct_buffer_length), 1903 ct.byref(ct_buffer) 1904 ) 1905 1906 if status not in successes.success_codes: 1907 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 1908 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1909 else: 1910 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 1911 1912 # Editor wrote to a buffer, convert it to bytes 1913 file_type_bytes = utils.buffer_to_bytes( 1914 ct_buffer, 1915 ct_buffer_length 1916 ) 1917 1918 file_type = file_type_bytes.decode() 1919 1920 return file_type 1921 1922 def GW2GetFileTypeID(self, session: int, file_type_str): 1923 """ Retrieve the Glasswall file type id given a file type string. 1924 1925 Args: 1926 session (int): The session integer. 1927 file_type_str (str): The file type as a string. 1928 1929 Returns: 1930 file_type_id (str): The Glasswall file type id for the specified file type. 1931 """ 1932 # Validate arg types 1933 if not isinstance(session, int): 1934 raise TypeError(session) 1935 1936 # API function declaration 1937 self.library.GW2GetFileTypeID.argtypes = [ 1938 ct.c_size_t, 1939 ct.c_char_p, 1940 ct.POINTER(ct.c_size_t), 1941 ct.POINTER(ct.c_void_p) 1942 ] 1943 1944 # Variable initialisation 1945 ct_session = ct.c_size_t(session) 1946 ct_file_type = ct.c_char_p(file_type_str.encode('utf-8')) 1947 ct_buffer_length = ct.c_size_t() 1948 ct_buffer = ct.c_void_p() 1949 1950 # API call 1951 status = self.library.GW2GetFileTypeID( 1952 ct_session, 1953 ct_file_type, 1954 ct.byref(ct_buffer_length), 1955 ct.byref(ct_buffer) 1956 ) 1957 1958 if status not in successes.success_codes: 1959 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 1960 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1961 else: 1962 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 1963 1964 # Editor wrote to a buffer, convert it to bytes 1965 file_type_bytes = utils.buffer_to_bytes( 1966 ct_buffer, 1967 ct_buffer_length 1968 ) 1969 1970 file_type_id = file_type_bytes.decode() 1971 1972 return file_type_id 1973 1974 def get_file_type_info(self, file_type: Union[str, int]): 1975 """ Retrieve information about a file type based on its identifier. 1976 1977 Args: 1978 file_type (Union[str, int]): The file type identifier. This can be either a string representing a file 1979 extension (e.g. 'bmp') or an integer corresponding to a file type (e.g. 29). 1980 1981 Returns: 1982 - file_type_info (Union[int, str]): Depending on the input 'file_type': 1983 - If `file_type` is a string (e.g. 'bmp'): 1984 - If the file type is recognised, returns an integer corresponding to that file type. 1985 - If the file type is not recognised, returns 0. 1986 - If `file_type` is an integer (e.g. 29): 1987 - If the integer corresponds to a recognised file type, returns a more detailed string description 1988 of the file type (e.g. 'BMP Image'). 1989 - If the integer does not match any recognised file type, returns an empty string. 1990 """ 1991 # Validate arg types 1992 if not isinstance(file_type, (str, int)): 1993 raise TypeError(file_type) 1994 1995 with utils.CwdHandler(self.library_path): 1996 with self.new_session() as session: 1997 1998 if isinstance(file_type, int): 1999 file_type_info = self.GW2GetFileType(session, file_type) 2000 if isinstance(file_type, str): 2001 file_type_info = self.GW2GetFileTypeID(session, file_type) 2002 2003 return file_type_info 2004 2005 @utils.deprecated_function(replacement_function=get_file_type_info) 2006 def get_file_info(self, *args, **kwargs): 2007 """ Deprecated in 1.0.6. Use get_file_type_info. """ 2008 pass 2009 2010 def _GW2RegisterReportFile(self, session: int, output_file: str): 2011 """ Register an output report file path for the given session. 2012 2013 Args: 2014 session (int): The session integer. 2015 output_file (str): The file path of the output report file. 2016 2017 Returns: 2018 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2019 """ 2020 # API function declaration 2021 self.library.GW2RegisterReportFile.argtypes = [ 2022 ct.c_size_t, # Session_Handle session 2023 ct.c_char_p, # const char * reportFilePathName 2024 ] 2025 2026 # Variable initialisation 2027 gw_return_object = glasswall.GwReturnObj() 2028 gw_return_object.session = ct.c_size_t(session) 2029 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 2030 2031 # API call 2032 gw_return_object.status = self.library.GW2RegisterReportFile( 2033 gw_return_object.session, 2034 gw_return_object.output_file 2035 ) 2036 2037 return gw_return_object 2038 2039 def register_report_file(self, session: int, output_file: str): 2040 """ Register the report file path for the given session. 2041 2042 Args: 2043 session (int): The session integer. 2044 output_file (str): The file path of the report file. 2045 2046 Returns: 2047 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2048 """ 2049 # Validate arg types 2050 if not isinstance(session, int): 2051 raise TypeError(session) 2052 if not isinstance(output_file, (type(None), str)): 2053 raise TypeError(output_file) 2054 2055 result = self._GW2RegisterReportFile(session, output_file) 2056 2057 if result.status not in successes.success_codes: 2058 log.error(format_object(result)) 2059 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2060 else: 2061 log.debug(format_object(result)) 2062 2063 return result 2064 2065 def _GW2GetIdInfo(self, session: int, issue_id: int): 2066 """ Retrieves the group description for the given Issue ID. e.g. issue_id 96 returns "Document Processing Instances" 2067 2068 Args: 2069 session (int): The session integer. 2070 issue_id (int): The issue id. 2071 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2072 2073 Returns: 2074 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'issue_id', 'buffer_length', 'buffer', 'status', 'id_info'. 2075 """ 2076 # API function declaration 2077 self.library.GW2GetIdInfo.argtypes = [ 2078 ct.c_size_t, # Session_Handle session 2079 ct.c_size_t, # size_t issueId 2080 ct.POINTER(ct.c_size_t), # size_t * bufferLength 2081 ct.POINTER(ct.c_void_p) # char ** outputBuffer 2082 ] 2083 2084 # Variable initialisation 2085 gw_return_object = glasswall.GwReturnObj() 2086 gw_return_object.session = ct.c_size_t(session) 2087 gw_return_object.issue_id = ct.c_size_t(issue_id) 2088 gw_return_object.buffer_length = ct.c_size_t() 2089 gw_return_object.buffer = ct.c_void_p() 2090 2091 # API call 2092 gw_return_object.status = self.library.GW2GetIdInfo( 2093 gw_return_object.session, 2094 gw_return_object.issue_id, 2095 ct.byref(gw_return_object.buffer_length), 2096 ct.byref(gw_return_object.buffer) 2097 ) 2098 2099 # Editor wrote to a buffer, convert it to bytes 2100 id_info_bytes = utils.buffer_to_bytes( 2101 gw_return_object.buffer, 2102 gw_return_object.buffer_length 2103 ) 2104 2105 gw_return_object.id_info = id_info_bytes.decode() 2106 2107 return gw_return_object 2108 2109 def get_id_info(self, issue_id: int, raise_unsupported: bool = True): 2110 """ Retrieves the group description for the given Issue ID. e.g. issue_id 96 returns "Document Processing Instances" 2111 2112 Args: 2113 issue_id (int): The issue id. 2114 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2115 2116 Returns: 2117 id_info (str): The group description for the given Issue ID. 2118 """ 2119 # Validate arg types 2120 if not isinstance(issue_id, int): 2121 raise TypeError(issue_id) 2122 2123 with utils.CwdHandler(self.library_path): 2124 with self.new_session() as session: 2125 result = self._GW2GetIdInfo(session, issue_id) 2126 2127 if result.status not in successes.success_codes: 2128 log.error(format_object(result)) 2129 if raise_unsupported: 2130 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2131 else: 2132 log.debug(format_object(result)) 2133 2134 return result.id_info 2135 2136 def _GW2GetAllIdInfo(self, session: int): 2137 """ Retrieves the XML containing all the Issue ID ranges with their group descriptions 2138 2139 Args: 2140 session (int): The session integer. 2141 2142 Returns: 2143 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'analysis_format', 'status', 'all_id_info'. 2144 """ 2145 2146 # API function declaration 2147 self.library.GW2GetAllIdInfo.argtypes = [ 2148 ct.c_size_t, # Session_Handle session 2149 ct.POINTER(ct.c_size_t), # size_t * bufferLength 2150 ct.POINTER(ct.c_void_p) # char ** outputBuffer 2151 ] 2152 2153 # Variable initialisation 2154 # The extracted issue Id information is stored in the analysis report, register an analysis session. 2155 gw_return_object = self._GW2RegisterAnalysisMemory(session) 2156 2157 # API call 2158 gw_return_object.status = self.library.GW2GetAllIdInfo( 2159 gw_return_object.session, 2160 ct.byref(gw_return_object.buffer_length), 2161 ct.byref(gw_return_object.buffer) 2162 ) 2163 2164 # Editor wrote to a buffer, convert it to bytes 2165 all_id_info_bytes = utils.buffer_to_bytes( 2166 gw_return_object.buffer, 2167 gw_return_object.buffer_length 2168 ) 2169 2170 gw_return_object.all_id_info = all_id_info_bytes.decode() 2171 2172 return gw_return_object 2173 2174 def get_all_id_info(self, output_file: Optional[str] = None, raise_unsupported: bool = True) -> str: 2175 """ Retrieves the XML containing all the Issue ID ranges with their group descriptions 2176 2177 Args: 2178 output_file (Optional[str]): The output file path where the analysis file will be written. 2179 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2180 2181 Returns: 2182 all_id_info (str): A string XML analysis report containing all id info. 2183 """ 2184 # Validate arg types 2185 if not isinstance(output_file, (type(None), str)): 2186 raise TypeError(output_file) 2187 if isinstance(output_file, str): 2188 output_file = os.path.abspath(output_file) 2189 2190 with utils.CwdHandler(self.library_path): 2191 with self.new_session() as session: 2192 result = self._GW2GetAllIdInfo(session) 2193 2194 if result.status not in successes.success_codes: 2195 log.error(format_object(result)) 2196 if raise_unsupported: 2197 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2198 else: 2199 log.debug(format_object(result)) 2200 2201 if isinstance(output_file, str): 2202 # GW2GetAllIdInfo is memory only, write to file 2203 # make directories that do not exist 2204 os.makedirs(os.path.dirname(output_file), exist_ok=True) 2205 with open(output_file, "w") as f: 2206 f.write(result.all_id_info) 2207 2208 return result.all_id_info 2209 2210 def _GW2FileSessionStatus(self, session: int): 2211 """ Retrieves the Glasswall Session Status. Also gives a high level indication of the processing that was carried out on the last document processed by the library 2212 2213 Args: 2214 session (int): The session integer. 2215 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2216 2217 Returns: 2218 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'session_status', 'buffer', 'buffer_length', 'status', 'message'. 2219 """ 2220 # API function declaration 2221 self.library.GW2FileSessionStatus.argtypes = [ 2222 ct.c_size_t, # Session_Handle session 2223 ct.POINTER(ct.c_int), # int *glasswallSessionStatus 2224 ct.POINTER(ct.c_void_p), # char **statusMsgBuffer 2225 ct.POINTER(ct.c_size_t) # size_t *statusbufferLength 2226 ] 2227 2228 # Variable initialisation 2229 gw_return_object = glasswall.GwReturnObj() 2230 gw_return_object.session = ct.c_size_t(session) 2231 gw_return_object.session_status = ct.c_int() 2232 gw_return_object.buffer = ct.c_void_p() 2233 gw_return_object.buffer_length = ct.c_size_t() 2234 2235 # API call 2236 gw_return_object.status = self.library.GW2FileSessionStatus( 2237 gw_return_object.session, 2238 ct.byref(gw_return_object.session_status), 2239 ct.byref(gw_return_object.buffer), 2240 ct.byref(gw_return_object.buffer_length) 2241 ) 2242 2243 # Convert session_status to int 2244 gw_return_object.session_status = gw_return_object.session_status.value 2245 2246 # Editor wrote to a buffer, convert it to bytes 2247 message_bytes = utils.buffer_to_bytes( 2248 gw_return_object.buffer, 2249 gw_return_object.buffer_length 2250 ) 2251 gw_return_object.message = message_bytes.decode() 2252 2253 return gw_return_object 2254 2255 def file_session_status_message(self, session: int, raise_unsupported: bool = True) -> str: 2256 """ Retrieves the Glasswall session status message. Gives a high level indication of the processing that was carried out. 2257 2258 Args: 2259 session (int): The session integer. 2260 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2261 2262 Returns: 2263 result.message (str):The file session status message. 2264 """ 2265 # Validate arg types 2266 if not isinstance(session, int): 2267 raise TypeError(session) 2268 2269 result = self._GW2FileSessionStatus(session) 2270 2271 if result.status not in successes.success_codes: 2272 log.error(format_object(result)) 2273 if raise_unsupported: 2274 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2275 else: 2276 log.debug(format_object(result)) 2277 2278 return result.message 2279 2280 def _GW2LicenceDetails(self, session: int): 2281 """ Returns a human readable string containing licence details. 2282 2283 Args: 2284 session (int): The session integer. 2285 2286 Returns: 2287 licence_details (str): A human readable string representing the relevant information contained in the licence. 2288 """ 2289 # API function declaration 2290 self.library.GW2LicenceDetails.argtypes = [ct.c_size_t] 2291 self.library.GW2LicenceDetails.restype = ct.c_char_p 2292 2293 # Variable initialisation 2294 ct_session = ct.c_size_t(session) 2295 2296 # API call 2297 licence_details = self.library.GW2LicenceDetails(ct_session) 2298 2299 # Convert to Python string 2300 licence_details = ct.string_at(licence_details).decode() 2301 2302 return licence_details 2303 2304 def licence_details(self): 2305 """ Returns a string containing details of the licence. 2306 2307 Returns: 2308 result (str): A string containing details of the licence. 2309 """ 2310 with self.new_session() as session: 2311 result = self._GW2LicenceDetails(session) 2312 2313 log.debug(f"\n\tsession: {session}\n\tGW2LicenceDetails: {result}") 2314 2315 return result 2316 2317 def _GW2RegisterExportTextDumpMemory(self, session: int): 2318 """ Registers an export text dump to be written in memory. 2319 2320 Args: 2321 session (int): The session integer. 2322 2323 Returns: 2324 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2325 """ 2326 # API function declaration 2327 self.library.GW2RegisterExportTextDumpMemory.argtypes = [ 2328 ct.c_size_t, # Session_Handle session 2329 ct.POINTER(ct.c_void_p), # char ** exportTextDumpFileBuffer 2330 ct.POINTER(ct.c_size_t) # size_t * exportTextDumpLength 2331 ] 2332 2333 # Variable initialisation 2334 gw_return_object = glasswall.GwReturnObj() 2335 gw_return_object.session = ct.c_size_t(session) 2336 gw_return_object.buffer = ct.c_void_p() 2337 gw_return_object.buffer_length = ct.c_size_t() 2338 2339 # API call 2340 gw_return_object.status = self.library.GW2RegisterExportTextDumpMemory( 2341 gw_return_object.session, 2342 ct.byref(gw_return_object.buffer), 2343 ct.byref(gw_return_object.buffer_length) 2344 ) 2345 2346 return gw_return_object 2347 2348 def _GW2RegisterExportTextDumpFile(self, session: int, output_file: str): 2349 """ Registers an export text dump to be written to file. 2350 2351 Args: 2352 session (int): The session integer. 2353 output_file (str): The file path of the text dump file. 2354 2355 Returns: 2356 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2357 """ 2358 # API function declaration 2359 self.library.GW2RegisterExportTextDumpFile.argtypes = [ 2360 ct.c_size_t, # Session_Handle session 2361 ct.c_char_p # const char * textDumpFilePathName 2362 ] 2363 2364 # Variable initialisation 2365 gw_return_object = glasswall.GwReturnObj() 2366 gw_return_object.session = ct.c_size_t(session) 2367 gw_return_object.output_file = ct.c_char_p(output_file.encode("utf-8")) 2368 2369 # API call 2370 gw_return_object.status = self.library.GW2RegisterExportTextDumpFile( 2371 gw_return_object.session, 2372 gw_return_object.output_file 2373 ) 2374 2375 return gw_return_object 2376 2377 def _GW2RegisterLicenceFile(self, session: int, input_file: str): 2378 """ Registers a "gwkey.lic" licence from file path. 2379 2380 Args: 2381 session (int): The session integer. 2382 input_file (str): The "gwkey.lic" licence input file path. 2383 2384 Returns: 2385 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 2386 """ 2387 # API function declaration 2388 self.library.GW2RegisterLicenceFile.argtypes = [ 2389 ct.c_size_t, # Session_Handle session 2390 ct.c_char_p, # const char *filename 2391 ] 2392 2393 # Variable initialisation 2394 gw_return_object = glasswall.GwReturnObj() 2395 gw_return_object.session = ct.c_size_t(session) 2396 gw_return_object.input_file = ct.c_char_p(input_file.encode("utf-8")) 2397 2398 # API call 2399 gw_return_object.status = self.library.GW2RegisterLicenceFile( 2400 gw_return_object.session, 2401 gw_return_object.input_file, 2402 ) 2403 2404 return gw_return_object 2405 2406 def _GW2RegisterLicenceMemory(self, session: int, input_file: bytes): 2407 """ Registers a "gwkey.lic" licence from memory. 2408 2409 Args: 2410 session (int): The session integer. 2411 input_file (bytes): The "gwkey.lic" licence input file. 2412 2413 Returns: 2414 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2415 """ 2416 # API function declaration 2417 self.library.GW2RegisterLicenceMemory.argtypes = [ 2418 ct.c_size_t, # Session_Handle session 2419 ct.c_char_p, # const char *filename 2420 ct.c_size_t, # size_t licenceLength 2421 ] 2422 2423 # Variable initialisation 2424 gw_return_object = glasswall.GwReturnObj() 2425 gw_return_object.session = ct.c_size_t(session) 2426 gw_return_object.buffer = ct.c_char_p(input_file) 2427 gw_return_object.buffer_length = ct.c_size_t(len(input_file)) 2428 2429 # API call 2430 gw_return_object.status = self.library.GW2RegisterLicenceMemory( 2431 gw_return_object.session, 2432 gw_return_object.buffer, 2433 gw_return_object.buffer_length 2434 ) 2435 2436 return gw_return_object 2437 2438 def register_licence(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 2439 """ Registers a "gwkey.lic" licence from file path or memory. 2440 2441 Args: 2442 session (int): The session integer. 2443 input_file (Union[str, bytes, bytearray, io.BytesIO]): The "gwkey.lic" licence. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. 2444 2445 Returns: 2446 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 2447 - If input_file is a str file path: 2448 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 2449 2450 - If input_file is a file in memory: 2451 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2452 """ 2453 if isinstance(input_file, str): 2454 if not os.path.isfile(input_file): 2455 raise FileNotFoundError(input_file) 2456 2457 input_file = os.path.abspath(input_file) 2458 2459 result = self._GW2RegisterLicenceFile(session, input_file) 2460 2461 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 2462 # Convert bytearray and io.BytesIO to bytes 2463 input_file = utils.as_bytes(input_file) 2464 2465 result = self._GW2RegisterLicenceMemory(session, input_file) 2466 2467 else: 2468 raise TypeError(input_file) 2469 2470 if result.status not in successes.success_codes: 2471 log.error(format_object(result)) 2472 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2473 else: 2474 log.debug(format_object(result)) 2475 2476 return result
A high level Python wrapper for Glasswall Editor / Core2.
22 def __init__(self, library_path: str, licence: Union[str, bytes, bytearray, io.BytesIO] = None): 23 """ Initialise the Editor instance. 24 25 Args: 26 library_path (str): The file or directory path to the Editor library. 27 licence (str, bytes, bytearray, or io.BytesIO, optional): The licence file content or path. This can be: 28 - A string representing the file path to the licence. 29 - A `bytes` or `bytearray` object containing the licence data. 30 - An `io.BytesIO` object for in-memory licence data. 31 If not specified, it is assumed that the licence file is located in the same directory as the `library_path`. 32 """ 33 super().__init__(library_path) 34 self.library = self.load_library(os.path.abspath(library_path)) 35 self.licence = licence 36 37 # Validate killswitch has not activated 38 self.validate_licence() 39 40 log.info(f"Loaded Glasswall {self.__class__.__name__} version {self.version()} from {self.library_path}")
Initialise the Editor instance.
Args:
library_path (str): The file or directory path to the Editor library.
licence (str, bytes, bytearray, or io.BytesIO, optional): The licence file content or path. This can be:
- A string representing the file path to the licence.
- A bytes
or bytearray
object containing the licence data.
- An io.BytesIO
object for in-memory licence data.
If not specified, it is assumed that the licence file is located in the same directory as the library_path
.
42 def validate_licence(self): 43 """ Validates the licence of the library by checking the licence details. 44 45 Raises: 46 LicenceExpired: If the licence has expired or could not be validated. 47 """ 48 licence_details = self.licence_details() 49 50 bad_details = [ 51 "Unable to Read Licence Key File", 52 "Licence File Missing Required Contents", 53 "Licence Expired", 54 ] 55 56 if any(bad_detail.lower() in licence_details.lower() for bad_detail in bad_details): 57 # bad_details found in licence_details 58 log.error(f"{self.__class__.__name__} licence validation failed. Licence details:\n{licence_details}") 59 raise errors.LicenceExpired(licence_details) 60 else: 61 log.debug(f"{self.__class__.__name__} licence validated successfully. Licence details:\n{licence_details}")
Validates the licence of the library by checking the licence details.
Raises: LicenceExpired: If the licence has expired or could not be validated.
63 def version(self): 64 """ Returns the Glasswall library version. 65 66 Returns: 67 version (str): The Glasswall library version. 68 """ 69 # API function declaration 70 self.library.GW2LibVersion.restype = ct.c_char_p 71 72 # API call 73 version = self.library.GW2LibVersion() 74 75 # Convert to Python string 76 version = ct.string_at(version).decode() 77 78 return version
Returns the Glasswall library version.
Returns: version (str): The Glasswall library version.
80 def open_session(self): 81 """ Open a new Glasswall session. 82 83 Returns: 84 session (int): An incrementing integer repsenting the current session. 85 """ 86 # API call 87 session = self.library.GW2OpenSession() 88 89 log.debug(f"\n\tsession: {session}") 90 91 if self.licence: 92 # Must register licence on each GW2OpenSession if the licence is not in the same directory as the library 93 self.register_licence(session, self.licence) 94 95 return session
Open a new Glasswall session.
Returns: session (int): An incrementing integer repsenting the current session.
97 def close_session(self, session: int) -> int: 98 """ Close the Glasswall session. All resources allocated by the session will be destroyed. 99 100 Args: 101 session (int): The session to close. 102 103 Returns: 104 status (int): The status code of the function call. 105 """ 106 if not isinstance(session, int): 107 raise TypeError(session) 108 109 # API function declaration 110 self.library.GW2CloseSession.argtypes = [ct.c_size_t] 111 112 # Variable initialisation 113 ct_session = ct.c_size_t(session) 114 115 # API call 116 status = self.library.GW2CloseSession(ct_session) 117 118 if status not in successes.success_codes: 119 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 120 else: 121 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 122 123 return status
Close the Glasswall session. All resources allocated by the session will be destroyed.
Args: session (int): The session to close.
Returns: status (int): The status code of the function call.
125 @contextmanager 126 def new_session(self): 127 """ Context manager. Opens a new session on entry and closes the session on exit. """ 128 try: 129 session = self.open_session() 130 yield session 131 finally: 132 self.close_session(session)
Context manager. Opens a new session on entry and closes the session on exit.
134 def run_session(self, session): 135 """ Runs the Glasswall session and begins processing of a file. 136 137 Args: 138 session (int): The session to run. 139 140 Returns: 141 status (int): The status code of the function call. 142 """ 143 # API function declaration 144 self.library.GW2RunSession.argtypes = [ct.c_size_t] 145 146 # Variable initialisation 147 ct_session = ct.c_size_t(session) 148 149 # API call 150 status = self.library.GW2RunSession(ct_session) 151 152 if status not in successes.success_codes: 153 log.error(f"\n\tsession: {session}\n\tstatus: {status}\n\tGW2FileErrorMsg: {self.file_error_message(session)}") 154 else: 155 log.debug(f"\n\tsession: {session}\n\tstatus: {status}\n\tGW2FileErrorMsg: {self.file_error_message(session)}") 156 157 return status
Runs the Glasswall session and begins processing of a file.
Args: session (int): The session to run.
Returns: status (int): The status code of the function call.
159 def determine_file_type(self, input_file: Union[str, bytes, bytearray, io.BytesIO], as_string: bool = False, raise_unsupported: bool = True) -> Union[int, str]: 160 """ Determine the file type of a given input file, either as an integer identifier or a string. 161 162 Args: 163 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file to analyse. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. 164 as_string (bool, optional): Return file type as string, eg: "bmp" instead of: 29. Defaults to False. 165 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 166 167 Returns: 168 file_type (Union[int, str]): The file type. 169 """ 170 if isinstance(input_file, str): 171 if not os.path.isfile(input_file): 172 raise FileNotFoundError(input_file) 173 174 # convert to ct.c_char_p of bytes 175 ct_input_file = ct.c_char_p(input_file.encode("utf-8")) 176 177 # API call 178 file_type = self.library.GW2DetermineFileTypeFromFile(ct_input_file) 179 180 elif isinstance(input_file, (bytes, bytearray, io.BytesIO)): 181 # convert to bytes 182 bytes_input_file = utils.as_bytes(input_file) 183 184 # ctypes conversion 185 ct_buffer = ct.c_char_p(bytes_input_file) 186 ct_buffer_length = ct.c_size_t(len(bytes_input_file)) 187 188 # API call 189 file_type = self.library.GW2DetermineFileTypeFromMemory( 190 ct_buffer, 191 ct_buffer_length 192 ) 193 194 else: 195 raise TypeError(input_file) 196 197 file_type_as_string = dft.file_type_int_to_str(file_type) 198 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 199 200 if not dft.is_success(file_type): 201 log.warning(f"\n\tfile_type: {file_type}\n\tfile_type_as_string: {file_type_as_string}\n\tinput_file: {input_file_repr}") 202 if raise_unsupported: 203 raise dft.int_class_map.get(file_type, dft.errors.UnknownErrorCode)(file_type) 204 else: 205 log.debug(f"\n\tfile_type: {file_type}\n\tfile_type_as_string: {file_type_as_string}\n\tinput_file: {input_file_repr}") 206 207 if as_string: 208 return file_type_as_string 209 210 return file_type
Determine the file type of a given input file, either as an integer identifier or a string.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file to analyse. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. as_string (bool, optional): Return file type as string, eg: "bmp" instead of: 29. Defaults to False. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: file_type (Union[int, str]): The file type.
255 def get_content_management_policy(self, session: int): 256 """ Returns the content management configuration for a given session. 257 258 Args: 259 session (int): The session integer. 260 261 Returns: 262 xml_string (str): The XML string of the current content management configuration. 263 """ 264 # NOTE GW2GetPolicySettings is current not implemented in editor 265 266 # set xml_string as loaded default config 267 xml_string = glasswall.content_management.policies.Editor(default="sanitise").text, 268 269 # log.debug(f"xml_string:\n{xml_string}") 270 271 return xml_string 272 273 # # API function declaration 274 # self.library.GW2GetPolicySettings.argtypes = [ 275 # ct.c_size_t, 276 # ct.c_void_p, 277 # ] 278 279 # # Variable initialisation 280 # ct_session = ct.c_size_t(session) 281 # ct_buffer = ct.c_void_p() 282 # ct_buffer_length = ct.c_size_t() 283 # # ct_file_format = ct.c_int(file_format) 284 285 # # API Call 286 # status = self.library.GW2GetPolicySettings( 287 # ct_session, 288 # ct.byref(ct_buffer), 289 # ct.byref(ct_buffer_length) 290 # ) 291 292 # print("GW2GetPolicySettings status:", status) 293 294 # file_bytes = utils.buffer_to_bytes( 295 # ct_buffer, 296 # ct_buffer_length, 297 # ) 298 299 # return file_bytes
Returns the content management configuration for a given session.
Args: session (int): The session integer.
Returns: xml_string (str): The XML string of the current content management configuration.
369 def set_content_management_policy(self, session: int, input_file: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, policy_format=0): 370 """ Sets the content management policy configuration. If input_file is None then default settings (sanitise) are applied. 371 372 Args: 373 session (int): The session integer. 374 input_file (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 375 policy_format (int): The format of the content management policy. 0=XML. 376 377 Returns: 378 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 379 - If input_file is a str file path: 380 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'policy_format', 'status'. 381 382 - If input_file is a file in memory: 383 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status'. 384 """ 385 # Validate type 386 if not isinstance(session, int): 387 raise TypeError(session) 388 if not isinstance(input_file, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 389 raise TypeError(input_file) 390 if not isinstance(policy_format, int): 391 raise TypeError(policy_format) 392 393 # Set input_file to default if input_file is None 394 if input_file is None: 395 input_file = glasswall.content_management.policies.Editor(default="sanitise") 396 397 # Validate xml content is parsable 398 utils.validate_xml(input_file) 399 400 # From file 401 if isinstance(input_file, str) and os.path.isfile(input_file): 402 input_file = os.path.abspath(input_file) 403 404 result = self._GW2RegisterPoliciesFile(session, input_file) 405 406 # From memory 407 elif isinstance(input_file, (str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 408 # Convert bytearray, io.BytesIO to bytes 409 if isinstance(input_file, (bytearray, io.BytesIO)): 410 input_file = utils.as_bytes(input_file) 411 # Convert string xml or Policy to bytes 412 if isinstance(input_file, (str, glasswall.content_management.policies.policy.Policy)): 413 input_file = input_file.encode("utf-8") 414 415 result = self._GW2RegisterPoliciesMemory(session, input_file) 416 417 if result.status not in successes.success_codes: 418 log.error(format_object(result)) 419 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 420 else: 421 log.debug(format_object(result)) 422 423 return result
Sets the content management policy configuration. If input_file is None then default settings (sanitise) are applied.
Args: session (int): The session integer. input_file (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. policy_format (int): The format of the content management policy. 0=XML.
Returns: - result (glasswall.GwReturnObj): Depending on the input 'input_file': - If input_file is a str file path: - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'policy_format', 'status'.
- If input_file is a file in memory:
- gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'policy_format', 'status'.
487 def register_input(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 488 """ Register an input file or bytes for the given session. 489 490 Args: 491 session (int): The session integer. 492 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 493 494 Returns: 495 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 496 - If input_file is a str file path: 497 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 498 499 - If input_file is a file in memory: 500 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 501 """ 502 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO,)): 503 raise TypeError(input_file) 504 505 if isinstance(input_file, str): 506 if not os.path.isfile(input_file): 507 raise FileNotFoundError(input_file) 508 509 input_file = os.path.abspath(input_file) 510 511 result = self._GW2RegisterInputFile(session, input_file) 512 513 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 514 # Convert bytearray and io.BytesIO to bytes 515 input_file = utils.as_bytes(input_file) 516 517 result = self._GW2RegisterInputMemory(session, input_file) 518 519 if result.status not in successes.success_codes: 520 log.error(format_object(result)) 521 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 522 else: 523 log.debug(format_object(result)) 524 525 return result
Register an input file or bytes for the given session.
Args: session (int): The session integer. input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes.
Returns: - result (glasswall.GwReturnObj): Depending on the input 'input_file': - If input_file is a str file path: - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'.
- If input_file is a file in memory:
- gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'.
587 def register_output(self, session, output_file: Optional[str] = None): 588 """ Register an output file for the given session. If output_file is None the file will be returned as 'buffer' and 'buffer_length' attributes. 589 590 Args: 591 session (int): The session integer. 592 output_file (Optional[str]): If specified, during run session the file will be written to output_file, otherwise the file will be written to the glasswall.GwReturnObj 'buffer' and 'buffer_length' attributes. 593 594 Returns: 595 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 596 """ 597 if not isinstance(output_file, (type(None), str)): 598 raise TypeError(output_file) 599 600 if isinstance(output_file, str): 601 output_file = os.path.abspath(output_file) 602 603 result = self._GW2RegisterOutFile(session, output_file) 604 605 elif isinstance(output_file, type(None)): 606 result = self._GW2RegisterOutputMemory(session) 607 608 if result.status not in successes.success_codes: 609 log.error(format_object(result)) 610 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 611 else: 612 log.debug(format_object(result)) 613 614 return result
Register an output file for the given session. If output_file is None the file will be returned as 'buffer' and 'buffer_length' attributes.
Args: session (int): The session integer. output_file (Optional[str]): If specified, during run session the file will be written to output_file, otherwise the file will be written to the glasswall.GwReturnObj 'buffer' and 'buffer_length' attributes.
Returns: gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size.
684 def register_analysis(self, session: int, output_file: Optional[str] = None): 685 """ Registers an analysis file for the given session. The analysis file will be created during the session's run_session call. 686 687 Args: 688 session (int): The session integer. 689 output_file (Optional[str]): Default None. The file path where the analysis will be written. None returns the analysis as bytes. 690 691 Returns: 692 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'status', 'session', 'analysis_format'. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. If output_file is not None (file mode) 'output_file' is included. 693 """ 694 if not isinstance(output_file, (type(None), str)): 695 raise TypeError(output_file) 696 697 if isinstance(output_file, str): 698 output_file = os.path.abspath(output_file) 699 700 result = self._GW2RegisterAnalysisFile(session, output_file) 701 702 elif isinstance(output_file, type(None)): 703 result = self._GW2RegisterAnalysisMemory(session) 704 705 if result.status not in successes.success_codes: 706 log.error(format_object(result)) 707 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 708 else: 709 log.debug(format_object(result)) 710 711 return result
Registers an analysis file for the given session. The analysis file will be created during the session's run_session call.
Args: session (int): The session integer. output_file (Optional[str]): Default None. The file path where the analysis will be written. None returns the analysis as bytes.
Returns: gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'status', 'session', 'analysis_format'. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. If output_file is not None (file mode) 'output_file' is included.
713 def protect_file( 714 self, 715 input_file: Union[str, bytes, bytearray, io.BytesIO], 716 output_file: Optional[str] = None, 717 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 718 raise_unsupported: bool = True, 719 ): 720 """ Protects a file using the current content management configuration, returning the file bytes. The protected file is written to output_file if it is provided. 721 722 Args: 723 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 724 output_file (Optional[str]): The output file path where the protected file will be written. 725 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 726 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 727 728 Returns: 729 file_bytes (bytes): The protected file bytes. 730 """ 731 # Validate arg types 732 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 733 raise TypeError(input_file) 734 if not isinstance(output_file, (type(None), str)): 735 raise TypeError(output_file) 736 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 737 raise TypeError(content_management_policy) 738 if not isinstance(raise_unsupported, bool): 739 raise TypeError(raise_unsupported) 740 741 # Convert string path arguments to absolute paths 742 if isinstance(input_file, str): 743 if not os.path.isfile(input_file): 744 raise FileNotFoundError(input_file) 745 input_file = os.path.abspath(input_file) 746 if isinstance(output_file, str): 747 output_file = os.path.abspath(output_file) 748 # make directories that do not exist 749 os.makedirs(os.path.dirname(output_file), exist_ok=True) 750 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 751 content_management_policy = os.path.abspath(content_management_policy) 752 753 # Convert memory inputs to bytes 754 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 755 input_file = utils.as_bytes(input_file) 756 757 with utils.CwdHandler(self.library_path): 758 with self.new_session() as session: 759 content_management_policy = self.set_content_management_policy(session, content_management_policy) 760 register_input = self.register_input(session, input_file) 761 register_output = self.register_output(session, output_file=output_file) 762 status = self.run_session(session) 763 764 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 765 if status not in successes.success_codes: 766 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 767 if raise_unsupported: 768 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 769 else: 770 file_bytes = None 771 else: 772 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 773 # Get file bytes 774 if isinstance(output_file, str): 775 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 776 if not os.path.isfile(output_file): 777 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 778 file_bytes = None 779 else: 780 with open(output_file, "rb") as f: 781 file_bytes = f.read() 782 else: 783 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 784 file_bytes = utils.buffer_to_bytes( 785 register_output.buffer, 786 register_output.buffer_length 787 ) 788 789 # Ensure memory allocated is not garbage collected 790 content_management_policy, register_input, register_output 791 792 return file_bytes
Protects a file using the current content management configuration, returning the file bytes. The protected file is written to output_file if it is provided.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. output_file (Optional[str]): The output file path where the protected file will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: file_bytes (bytes): The protected file bytes.
794 def protect_directory( 795 self, 796 input_directory: str, 797 output_directory: Optional[str] = None, 798 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 799 raise_unsupported: bool = True, 800 ): 801 """ Recursively processes all files in a directory in protect mode using the given content management policy. 802 The protected files are written to output_directory maintaining the same directory structure as input_directory. 803 804 Args: 805 input_directory (str): The input directory containing files to protect. 806 output_directory (Optional[str]): The output directory where the protected file will be written, or None to not write files. 807 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 808 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 809 810 Returns: 811 protected_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 812 """ 813 protected_files_dict = {} 814 # Call protect_file on each file in input_directory to output_directory 815 for input_file in utils.list_file_paths(input_directory): 816 relative_path = os.path.relpath(input_file, input_directory) 817 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 818 819 protected_bytes = self.protect_file( 820 input_file=input_file, 821 output_file=output_file, 822 raise_unsupported=raise_unsupported, 823 content_management_policy=content_management_policy, 824 ) 825 826 protected_files_dict[relative_path] = protected_bytes 827 828 return protected_files_dict
Recursively processes all files in a directory in protect mode using the given content management policy. The protected files are written to output_directory maintaining the same directory structure as input_directory.
Args: input_directory (str): The input directory containing files to protect. output_directory (Optional[str]): The output directory where the protected file will be written, or None to not write files. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: protected_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes.
830 def analyse_file( 831 self, 832 input_file: Union[str, bytes, bytearray, io.BytesIO], 833 output_file: Optional[str] = None, 834 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 835 raise_unsupported: bool = True, 836 ): 837 """ Analyses a file, returning the analysis bytes. The analysis is written to output_file if it is provided. 838 839 Args: 840 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 841 output_file (Optional[str]): The output file path where the analysis file will be written. 842 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 843 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 844 845 Returns: 846 file_bytes (bytes): The analysis file bytes. 847 """ 848 # Validate arg types 849 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 850 raise TypeError(input_file) 851 if not isinstance(output_file, (type(None), str)): 852 raise TypeError(output_file) 853 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 854 raise TypeError(content_management_policy) 855 if not isinstance(raise_unsupported, bool): 856 raise TypeError(raise_unsupported) 857 858 # Convert string path arguments to absolute paths 859 if isinstance(input_file, str): 860 if not os.path.isfile(input_file): 861 raise FileNotFoundError(input_file) 862 input_file = os.path.abspath(input_file) 863 if isinstance(output_file, str): 864 output_file = os.path.abspath(output_file) 865 # make directories that do not exist 866 os.makedirs(os.path.dirname(output_file), exist_ok=True) 867 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 868 content_management_policy = os.path.abspath(content_management_policy) 869 870 # Convert memory inputs to bytes 871 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 872 input_file = utils.as_bytes(input_file) 873 874 with utils.CwdHandler(self.library_path): 875 with self.new_session() as session: 876 content_management_policy = self.set_content_management_policy(session, content_management_policy) 877 register_input = self.register_input(session, input_file) 878 register_analysis = self.register_analysis(session, output_file) 879 status = self.run_session(session) 880 881 file_bytes = None 882 if isinstance(output_file, str): 883 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 884 if os.path.isfile(output_file): 885 with open(output_file, "rb") as f: 886 file_bytes = f.read() 887 else: 888 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 889 if register_analysis.buffer and register_analysis.buffer_length: 890 file_bytes = utils.buffer_to_bytes( 891 register_analysis.buffer, 892 register_analysis.buffer_length 893 ) 894 895 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 896 if status not in successes.success_codes: 897 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 898 if raise_unsupported: 899 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 900 else: 901 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 902 903 # Ensure memory allocated is not garbage collected 904 content_management_policy, register_input, register_analysis 905 906 return file_bytes
Analyses a file, returning the analysis bytes. The analysis is written to output_file if it is provided.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. output_file (Optional[str]): The output file path where the analysis file will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: file_bytes (bytes): The analysis file bytes.
908 def analyse_directory( 909 self, 910 input_directory: str, 911 output_directory: Optional[str] = None, 912 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 913 raise_unsupported: bool = True, 914 ): 915 """ Analyses all files in a directory and its subdirectories. The analysis files are written to output_directory maintaining the same directory structure as input_directory. 916 917 Args: 918 input_directory (str): The input directory containing files to analyse. 919 output_directory (Optional[str]): The output directory where the analysis files will be written, or None to not write files. 920 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 921 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 922 923 Returns: 924 analysis_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 925 """ 926 analysis_files_dict = {} 927 # Call analyse_file on each file in input_directory to output_directory 928 for input_file in utils.list_file_paths(input_directory): 929 relative_path = os.path.relpath(input_file, input_directory) + ".xml" 930 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 931 932 analysis_bytes = self.analyse_file( 933 input_file=input_file, 934 output_file=output_file, 935 raise_unsupported=raise_unsupported, 936 content_management_policy=content_management_policy, 937 ) 938 939 analysis_files_dict[relative_path] = analysis_bytes 940 941 return analysis_files_dict
Analyses all files in a directory and its subdirectories. The analysis files are written to output_directory maintaining the same directory structure as input_directory.
Args: input_directory (str): The input directory containing files to analyse. output_directory (Optional[str]): The output directory where the analysis files will be written, or None to not write files. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: analysis_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes.
943 def protect_and_analyse_file( 944 self, 945 input_file: Union[str, bytes, bytearray, io.BytesIO], 946 output_file: Optional[str] = None, 947 output_analysis_report: Optional[str] = None, 948 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 949 raise_unsupported: bool = True, 950 ): 951 """ Protects and analyses a file in a single session, returning both protected file bytes and analysis report bytes. 952 953 Args: 954 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 955 output_file (Optional[str]): The output file path where the protected file will be written. 956 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 957 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 958 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 959 960 Returns: 961 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (protected_file_bytes, analysis_report_bytes). 962 """ 963 # Validate arg types 964 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 965 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 966 if not isinstance(output_file, (type(None), str)): 967 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 968 if not isinstance(output_analysis_report, (type(None), str)): 969 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 970 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 971 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 972 if not isinstance(raise_unsupported, bool): 973 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 974 975 # Convert string path arguments to absolute paths 976 if isinstance(input_file, str): 977 if not os.path.isfile(input_file): 978 raise FileNotFoundError(input_file) 979 input_file = os.path.abspath(input_file) 980 if isinstance(output_file, str): 981 output_file = os.path.abspath(output_file) 982 os.makedirs(os.path.dirname(output_file), exist_ok=True) 983 if isinstance(output_analysis_report, str): 984 output_analysis_report = os.path.abspath(output_analysis_report) 985 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 986 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 987 content_management_policy = os.path.abspath(content_management_policy) 988 989 # Convert memory inputs to bytes 990 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 991 input_file = utils.as_bytes(input_file) 992 993 with utils.CwdHandler(self.library_path): 994 with self.new_session() as session: 995 content_management_policy = self.set_content_management_policy(session, content_management_policy) 996 register_input = self.register_input(session, input_file) 997 register_output = self.register_output(session, output_file) 998 register_analysis = self.register_analysis(session, output_analysis_report) 999 1000 status = self.run_session(session) 1001 1002 protected_file_bytes = None 1003 analysis_report_bytes = None 1004 1005 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1006 if status not in successes.success_codes: 1007 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1008 if raise_unsupported: 1009 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1010 1011 # Get analysis report file bytes, even on processing failure 1012 if isinstance(output_analysis_report, str): 1013 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1014 if not os.path.isfile(output_analysis_report): 1015 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1016 else: 1017 with open(output_analysis_report, "rb") as f: 1018 analysis_report_bytes = f.read() 1019 else: 1020 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1021 if register_analysis.buffer and register_analysis.buffer_length: 1022 analysis_report_bytes = utils.buffer_to_bytes( 1023 register_analysis.buffer, 1024 register_analysis.buffer_length 1025 ) 1026 1027 # On success, get protected file bytes 1028 if status in successes.success_codes: 1029 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1030 # Get file bytes 1031 if isinstance(output_file, str): 1032 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1033 if not os.path.isfile(output_file): 1034 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1035 else: 1036 with open(output_file, "rb") as f: 1037 protected_file_bytes = f.read() 1038 else: 1039 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1040 protected_file_bytes = utils.buffer_to_bytes( 1041 register_output.buffer, 1042 register_output.buffer_length 1043 ) 1044 1045 # Ensure memory allocated is not garbage collected 1046 content_management_policy, register_input, register_output, register_analysis 1047 1048 return protected_file_bytes, analysis_report_bytes
Protects and analyses a file in a single session, returning both protected file bytes and analysis report bytes.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. output_file (Optional[str]): The output file path where the protected file will be written. output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: Tuple[Optional[bytes], Optional[bytes]]: A tuple of (protected_file_bytes, analysis_report_bytes).
1050 def protect_and_analyse_directory( 1051 self, 1052 input_directory: str, 1053 output_directory: Optional[str] = None, 1054 analysis_directory: Optional[str] = None, 1055 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1056 raise_unsupported: bool = True, 1057 ): 1058 """ Recursively processes all files in a directory using protect and analyse mode with the given content management policy. 1059 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1060 1061 Args: 1062 input_directory (str): The input directory containing files to process. 1063 output_directory (Optional[str]): The output directory for protected files. 1064 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1065 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1066 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1067 1068 Returns: 1069 result_dict (dict): A dictionary mapping relative file paths to tuples of (protected_file_bytes, analysis_report_bytes). 1070 """ 1071 result_dict = {} 1072 for input_file in utils.list_file_paths(input_directory): 1073 relative_path = os.path.relpath(input_file, input_directory) 1074 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1075 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1076 1077 protected_file_bytes, analysis_report_bytes = self.protect_and_analyse_file( 1078 input_file=input_file, 1079 output_file=output_file, 1080 output_analysis_report=output_analysis_report, 1081 content_management_policy=content_management_policy, 1082 raise_unsupported=raise_unsupported, 1083 ) 1084 1085 result_dict[relative_path] = (protected_file_bytes, analysis_report_bytes) 1086 1087 return result_dict
Recursively processes all files in a directory using protect and analyse mode with the given content management policy. Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory.
Args: input_directory (str): The input directory containing files to process. output_directory (Optional[str]): The output directory for protected files. analysis_directory (Optional[str]): The output directory for XML analysis reports. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: result_dict (dict): A dictionary mapping relative file paths to tuples of (protected_file_bytes, analysis_report_bytes).
1149 def register_export(self, session: int, output_file: Optional[str] = None): 1150 """ Registers a file to be exported for the given session. The export file will be created during the session's run_session call. 1151 1152 Args: 1153 session (int): The session integer. 1154 output_file (Optional[str]): Default None. The file path where the export will be written. None exports the file in memory. 1155 1156 Returns: 1157 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call and 'session', the session integer. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 1158 """ 1159 if not isinstance(output_file, (type(None), str)): 1160 raise TypeError(output_file) 1161 1162 if isinstance(output_file, str): 1163 output_file = os.path.abspath(output_file) 1164 1165 result = self._GW2RegisterExportFile(session, output_file) 1166 1167 elif isinstance(output_file, type(None)): 1168 result = self._GW2RegisterExportMemory(session) 1169 1170 if result.status not in successes.success_codes: 1171 log.error(format_object(result)) 1172 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1173 else: 1174 log.debug(format_object(result)) 1175 1176 return result
Registers a file to be exported for the given session. The export file will be created during the session's run_session call.
Args: session (int): The session integer. output_file (Optional[str]): Default None. The file path where the export will be written. None exports the file in memory.
Returns: gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call and 'session', the session integer. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size.
1178 def export_file( 1179 self, 1180 input_file: Union[str, bytes, bytearray, io.BytesIO], 1181 output_file: Optional[str] = None, 1182 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1183 raise_unsupported: bool = True, 1184 ): 1185 """ Export a file, returning the .zip file bytes. The .zip file is written to output_file if it is provided. 1186 1187 Args: 1188 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1189 output_file (Optional[str]): The output file path where the .zip file will be written. 1190 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1191 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1192 1193 Returns: 1194 file_bytes (bytes): The exported .zip file. 1195 """ 1196 # Validate arg types 1197 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1198 raise TypeError(input_file) 1199 if not isinstance(output_file, (type(None), str)): 1200 raise TypeError(output_file) 1201 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1202 raise TypeError(content_management_policy) 1203 if not isinstance(raise_unsupported, bool): 1204 raise TypeError(raise_unsupported) 1205 1206 # Convert string path arguments to absolute paths 1207 if isinstance(input_file, str): 1208 if not os.path.isfile(input_file): 1209 raise FileNotFoundError(input_file) 1210 input_file = os.path.abspath(input_file) 1211 if isinstance(output_file, str): 1212 output_file = os.path.abspath(output_file) 1213 # make directories that do not exist 1214 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1215 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1216 content_management_policy = os.path.abspath(content_management_policy) 1217 1218 # Convert memory inputs to bytes 1219 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1220 input_file = utils.as_bytes(input_file) 1221 1222 with utils.CwdHandler(self.library_path): 1223 with self.new_session() as session: 1224 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1225 register_input = self.register_input(session, input_file) 1226 register_export = self.register_export(session, output_file) 1227 status = self.run_session(session) 1228 1229 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1230 if status not in successes.success_codes: 1231 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1232 if raise_unsupported: 1233 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1234 else: 1235 file_bytes = None 1236 else: 1237 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1238 # Get file bytes 1239 if isinstance(output_file, str): 1240 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1241 if not os.path.isfile(output_file): 1242 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1243 file_bytes = None 1244 else: 1245 with open(output_file, "rb") as f: 1246 file_bytes = f.read() 1247 else: 1248 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1249 file_bytes = utils.buffer_to_bytes( 1250 register_export.buffer, 1251 register_export.buffer_length 1252 ) 1253 1254 # Ensure memory allocated is not garbage collected 1255 content_management_policy, register_input, register_export 1256 1257 return file_bytes
Export a file, returning the .zip file bytes. The .zip file is written to output_file if it is provided.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. output_file (Optional[str]): The output file path where the .zip file will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: file_bytes (bytes): The exported .zip file.
1259 def export_directory( 1260 self, 1261 input_directory: str, 1262 output_directory: Optional[str] = None, 1263 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1264 raise_unsupported: bool = True 1265 ): 1266 """ Exports all files in a directory and its subdirectories. The export files are written to output_directory maintaining the same directory structure as input_directory. 1267 1268 Args: 1269 input_directory (str): The input directory containing files to export. 1270 output_directory (Optional[str]): The output directory where the export files will be written, or None to not write files. 1271 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 1272 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1273 1274 Returns: 1275 export_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 1276 """ 1277 export_files_dict = {} 1278 # Call export_file on each file in input_directory to output_directory 1279 for input_file in utils.list_file_paths(input_directory): 1280 relative_path = os.path.relpath(input_file, input_directory) + ".zip" 1281 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1282 1283 export_bytes = self.export_file( 1284 input_file=input_file, 1285 output_file=output_file, 1286 raise_unsupported=raise_unsupported, 1287 content_management_policy=content_management_policy, 1288 ) 1289 1290 export_files_dict[relative_path] = export_bytes 1291 1292 return export_files_dict
Exports all files in a directory and its subdirectories. The export files are written to output_directory maintaining the same directory structure as input_directory.
Args: input_directory (str): The input directory containing files to export. output_directory (Optional[str]): The output directory where the export files will be written, or None to not write files. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: export_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes.
1294 def export_and_analyse_file( 1295 self, 1296 input_file: Union[str, bytes, bytearray, io.BytesIO], 1297 output_file: Optional[str] = None, 1298 output_analysis_report: Optional[str] = None, 1299 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1300 raise_unsupported: bool = True, 1301 ): 1302 """ Exports and analyses a file in a single session, returning both exported .zip bytes and analysis report bytes. 1303 1304 Args: 1305 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1306 output_file (Optional[str]): The output file path where the .zip export will be written. 1307 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 1308 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1309 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1310 1311 Returns: 1312 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (export_file_bytes, analysis_report_bytes). 1313 """ 1314 # Validate arg types 1315 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1316 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 1317 if not isinstance(output_file, (type(None), str)): 1318 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 1319 if not isinstance(output_analysis_report, (type(None), str)): 1320 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 1321 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1322 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 1323 if not isinstance(raise_unsupported, bool): 1324 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 1325 1326 # Convert string path arguments to absolute paths 1327 if isinstance(input_file, str): 1328 if not os.path.isfile(input_file): 1329 raise FileNotFoundError(input_file) 1330 input_file = os.path.abspath(input_file) 1331 if isinstance(output_file, str): 1332 output_file = os.path.abspath(output_file) 1333 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1334 if isinstance(output_analysis_report, str): 1335 output_analysis_report = os.path.abspath(output_analysis_report) 1336 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 1337 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1338 content_management_policy = os.path.abspath(content_management_policy) 1339 1340 # Convert memory inputs to bytes 1341 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1342 input_file = utils.as_bytes(input_file) 1343 1344 with utils.CwdHandler(self.library_path): 1345 with self.new_session() as session: 1346 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1347 register_input = self.register_input(session, input_file) 1348 register_export = self.register_export(session, output_file) 1349 register_analysis = self.register_analysis(session, output_analysis_report) 1350 1351 status = self.run_session(session) 1352 1353 export_file_bytes = None 1354 analysis_report_bytes = None 1355 1356 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1357 if status not in successes.success_codes: 1358 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1359 if raise_unsupported: 1360 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1361 1362 # Get analysis report file bytes, even on processing failure 1363 if isinstance(output_analysis_report, str): 1364 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1365 if not os.path.isfile(output_analysis_report): 1366 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1367 else: 1368 with open(output_analysis_report, "rb") as f: 1369 analysis_report_bytes = f.read() 1370 else: 1371 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1372 if register_analysis.buffer and register_analysis.buffer_length: 1373 analysis_report_bytes = utils.buffer_to_bytes( 1374 register_analysis.buffer, 1375 register_analysis.buffer_length 1376 ) 1377 1378 # On success, get export file bytes 1379 if status in successes.success_codes: 1380 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1381 # Get export file bytes 1382 if isinstance(output_file, str): 1383 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1384 if not os.path.isfile(output_file): 1385 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1386 else: 1387 with open(output_file, "rb") as f: 1388 export_file_bytes = f.read() 1389 else: 1390 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1391 export_file_bytes = utils.buffer_to_bytes( 1392 register_export.buffer, 1393 register_export.buffer_length 1394 ) 1395 1396 # Ensure memory allocated is not garbage collected 1397 content_management_policy, register_input, register_export, register_analysis 1398 1399 return export_file_bytes, analysis_report_bytes
Exports and analyses a file in a single session, returning both exported .zip bytes and analysis report bytes.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. output_file (Optional[str]): The output file path where the .zip export will be written. output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: Tuple[Optional[bytes], Optional[bytes]]: A tuple of (export_file_bytes, analysis_report_bytes).
1401 def export_and_analyse_directory( 1402 self, 1403 input_directory: str, 1404 output_directory: Optional[str] = None, 1405 analysis_directory: Optional[str] = None, 1406 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1407 raise_unsupported: bool = True, 1408 ): 1409 """ Recursively processes all files in a directory using export and analyse mode with the given content management policy. 1410 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1411 1412 Args: 1413 input_directory (str): The input directory containing files to process. 1414 output_directory (Optional[str]): The output directory for exported .zip files. 1415 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1416 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1417 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1418 1419 Returns: 1420 result_dict (dict): A dictionary mapping relative file paths to tuples of (export_file_bytes, analysis_report_bytes). 1421 """ 1422 result_dict = {} 1423 1424 for input_file in utils.list_file_paths(input_directory): 1425 relative_path = os.path.relpath(input_file, input_directory) 1426 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path + ".zip") 1427 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1428 1429 export_file_bytes, analysis_report_bytes = self.export_and_analyse_file( 1430 input_file=input_file, 1431 output_file=output_file, 1432 output_analysis_report=output_analysis_report, 1433 content_management_policy=content_management_policy, 1434 raise_unsupported=raise_unsupported, 1435 ) 1436 1437 result_dict[relative_path] = (export_file_bytes, analysis_report_bytes) 1438 1439 return result_dict
Recursively processes all files in a directory using export and analyse mode with the given content management policy. Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory.
Args: input_directory (str): The input directory containing files to process. output_directory (Optional[str]): The output directory for exported .zip files. analysis_directory (Optional[str]): The output directory for XML analysis reports. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: result_dict (dict): A dictionary mapping relative file paths to tuples of (export_file_bytes, analysis_report_bytes).
1502 def register_import(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 1503 """ Registers a .zip file to be imported for the given session. The constructed file will be created during the session's run_session call. 1504 1505 Args: 1506 session (int): The session integer. 1507 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input import file path or bytes. 1508 1509 Returns: 1510 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size. 1511 """ 1512 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO,)): 1513 raise TypeError(input_file) 1514 1515 if isinstance(input_file, str): 1516 if not os.path.isfile(input_file): 1517 raise FileNotFoundError(input_file) 1518 1519 input_file = os.path.abspath(input_file) 1520 1521 result = self._GW2RegisterImportFile(session, input_file) 1522 1523 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 1524 # Convert bytearray and io.BytesIO to bytes 1525 input_file = utils.as_bytes(input_file) 1526 1527 result = self._GW2RegisterImportMemory(session, input_file) 1528 1529 if result.status not in successes.success_codes: 1530 log.error(format_object(result)) 1531 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1532 else: 1533 log.debug(format_object(result)) 1534 1535 return result
Registers a .zip file to be imported for the given session. The constructed file will be created during the session's run_session call.
Args: session (int): The session integer. input_file (Union[str, bytes, bytearray, io.BytesIO]): The input import file path or bytes.
Returns: gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attribute 'status' indicating the result of the function call. If output_file is None (memory mode), 'buffer', and 'buffer_length' are included containing the file content and file size.
1537 def import_file( 1538 self, 1539 input_file: Union[str, bytes, bytearray, io.BytesIO], 1540 output_file: Optional[str] = None, 1541 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1542 raise_unsupported: bool = True, 1543 ): 1544 """ Import a .zip file, constructs a file from the .zip file and returns the file bytes. The file is written to output_file if it is provided. 1545 1546 Args: 1547 input_file (Union[str, bytes, bytearray, io.BytesIO]): The .zip input file path or bytes. 1548 output_file (Optional[str]): The output file path where the constructed file will be written. 1549 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1550 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1551 1552 Returns: 1553 file_bytes (bytes): The imported file bytes. 1554 """ 1555 # Validate arg types 1556 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1557 raise TypeError(input_file) 1558 if not isinstance(output_file, (type(None), str)): 1559 raise TypeError(output_file) 1560 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1561 raise TypeError(content_management_policy) 1562 if not isinstance(raise_unsupported, bool): 1563 raise TypeError(raise_unsupported) 1564 1565 # Convert string path arguments to absolute paths 1566 if isinstance(input_file, str): 1567 if not os.path.isfile(input_file): 1568 raise FileNotFoundError(input_file) 1569 input_file = os.path.abspath(input_file) 1570 if isinstance(output_file, str): 1571 output_file = os.path.abspath(output_file) 1572 # make directories that do not exist 1573 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1574 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1575 content_management_policy = os.path.abspath(content_management_policy) 1576 1577 # Convert memory inputs to bytes 1578 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1579 input_file = utils.as_bytes(input_file) 1580 1581 with utils.CwdHandler(self.library_path): 1582 with self.new_session() as session: 1583 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1584 register_import = self.register_import(session, input_file) 1585 register_output = self.register_output(session, output_file) 1586 status = self.run_session(session) 1587 1588 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray,)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1589 if status not in successes.success_codes: 1590 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1591 if raise_unsupported: 1592 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1593 else: 1594 file_bytes = None 1595 else: 1596 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\tsession: {session}\n\tstatus: {status}") 1597 # Get file bytes 1598 if isinstance(output_file, str): 1599 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1600 if not os.path.isfile(output_file): 1601 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1602 file_bytes = None 1603 else: 1604 with open(output_file, "rb") as f: 1605 file_bytes = f.read() 1606 else: 1607 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1608 file_bytes = utils.buffer_to_bytes( 1609 register_output.buffer, 1610 register_output.buffer_length 1611 ) 1612 1613 # Ensure memory allocated is not garbage collected 1614 content_management_policy, register_import, register_output 1615 1616 return file_bytes
Import a .zip file, constructs a file from the .zip file and returns the file bytes. The file is written to output_file if it is provided.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The .zip input file path or bytes. output_file (Optional[str]): The output file path where the constructed file will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: file_bytes (bytes): The imported file bytes.
1618 def import_directory( 1619 self, 1620 input_directory: str, 1621 output_directory: Optional[str] = None, 1622 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1623 raise_unsupported: bool = True, 1624 ): 1625 """ Imports all files in a directory and its subdirectories. Files are expected as .zip but this is not forced. 1626 The constructed files are written to output_directory maintaining the same directory structure as input_directory. 1627 1628 Args: 1629 input_directory (str): The input directory containing files to import. 1630 output_directory (Optional[str]): The output directory where the constructed files will be written, or None to not write files. 1631 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. 1632 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1633 1634 Returns: 1635 import_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes. 1636 """ 1637 import_files_dict = {} 1638 # Call import_file on each file in input_directory to output_directory 1639 for input_file in utils.list_file_paths(input_directory): 1640 relative_path = os.path.relpath(input_file, input_directory) 1641 # Remove .zip extension from relative_path 1642 if relative_path.endswith(".zip"): 1643 relative_path = os.path.splitext(relative_path)[0] 1644 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1645 1646 import_bytes = self.import_file( 1647 input_file=input_file, 1648 output_file=output_file, 1649 raise_unsupported=raise_unsupported, 1650 content_management_policy=content_management_policy, 1651 ) 1652 1653 import_files_dict[relative_path] = import_bytes 1654 1655 return import_files_dict
Imports all files in a directory and its subdirectories. Files are expected as .zip but this is not forced. The constructed files are written to output_directory maintaining the same directory structure as input_directory.
Args: input_directory (str): The input directory containing files to import. output_directory (Optional[str]): The output directory where the constructed files will be written, or None to not write files. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): Default None (sanitise). The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: import_files_dict (dict): A dictionary of file paths relative to input_directory, and file bytes.
1657 def import_and_analyse_file( 1658 self, 1659 input_file: Union[str, bytes, bytearray, io.BytesIO], 1660 output_file: Optional[str] = None, 1661 output_analysis_report: Optional[str] = None, 1662 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1663 raise_unsupported: bool = True, 1664 ): 1665 """ Imports and analyses a file in a single session, returning both imported file bytes and analysis report bytes. 1666 1667 Args: 1668 input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. 1669 output_file (Optional[str]): The output file path where the imported file will be written. 1670 output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. 1671 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. 1672 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1673 1674 Returns: 1675 Tuple[Optional[bytes], Optional[bytes]]: A tuple of (import_file_bytes, analysis_report_bytes). 1676 """ 1677 # Validate arg types 1678 if not isinstance(input_file, (str, bytes, bytearray, io.BytesIO)): 1679 raise TypeError(f"input_file expected to be of type: str, bytes, bytearray, io.BytesIO. Got: {type(input_file).__name__}") 1680 if not isinstance(output_file, (type(None), str)): 1681 raise TypeError(f"output_file expected to be of type: None, str. Got: {type(output_file).__name__}") 1682 if not isinstance(output_analysis_report, (type(None), str)): 1683 raise TypeError(f"output_analysis_report expected to be of type: None, str. Got: {type(output_analysis_report).__name__}") 1684 if not isinstance(content_management_policy, (type(None), str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy)): 1685 raise TypeError(f"content_management_policy expected to be of type: None, str, bytes, bytearray, io.BytesIO, Policy. Got: {type(content_management_policy).__name__}") 1686 if not isinstance(raise_unsupported, bool): 1687 raise TypeError(f"raise_unsupported expected to be of type: bool. Got: {type(raise_unsupported).__name__}") 1688 1689 # Convert string path arguments to absolute paths 1690 if isinstance(input_file, str): 1691 if not os.path.isfile(input_file): 1692 raise FileNotFoundError(input_file) 1693 input_file = os.path.abspath(input_file) 1694 if isinstance(output_file, str): 1695 output_file = os.path.abspath(output_file) 1696 os.makedirs(os.path.dirname(output_file), exist_ok=True) 1697 if isinstance(output_analysis_report, str): 1698 output_analysis_report = os.path.abspath(output_analysis_report) 1699 os.makedirs(os.path.dirname(output_analysis_report), exist_ok=True) 1700 if isinstance(content_management_policy, str) and os.path.isfile(content_management_policy): 1701 content_management_policy = os.path.abspath(content_management_policy) 1702 1703 # Convert memory inputs to bytes 1704 if isinstance(input_file, (bytes, bytearray, io.BytesIO)): 1705 input_file = utils.as_bytes(input_file) 1706 1707 with utils.CwdHandler(self.library_path): 1708 with self.new_session() as session: 1709 content_management_policy = self.set_content_management_policy(session, content_management_policy) 1710 register_import = self.register_import(session, input_file) 1711 register_output = self.register_output(session, output_file) 1712 register_analysis = self.register_analysis(session, output_analysis_report) 1713 1714 status = self.run_session(session) 1715 1716 import_file_bytes = None 1717 analysis_report_bytes = None 1718 1719 input_file_repr = f"{type(input_file)} length {len(input_file)}" if isinstance(input_file, (bytes, bytearray)) else input_file.__sizeof__() if isinstance(input_file, io.BytesIO) else input_file 1720 if status not in successes.success_codes: 1721 log.error(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1722 if raise_unsupported: 1723 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1724 1725 # Get analysis report file bytes, even on processing failure 1726 if isinstance(output_analysis_report, str): 1727 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1728 if not os.path.isfile(output_analysis_report): 1729 log.error(f"Editor returned success code: {status} but no output file was found: {output_analysis_report}") 1730 else: 1731 with open(output_analysis_report, "rb") as f: 1732 analysis_report_bytes = f.read() 1733 else: 1734 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1735 if register_analysis.buffer and register_analysis.buffer_length: 1736 analysis_report_bytes = utils.buffer_to_bytes( 1737 register_analysis.buffer, 1738 register_analysis.buffer_length 1739 ) 1740 1741 # On success, get import file bytes 1742 if status in successes.success_codes: 1743 log.debug(f"\n\tinput_file: {input_file_repr}\n\toutput_file: {output_file}\n\toutput_analysis_report: {output_analysis_report}\n\tsession: {session}\n\tstatus: {status}") 1744 # Get import file bytes 1745 if isinstance(output_file, str): 1746 # File to file and memory to file, Editor wrote to a file, read it to get the file bytes 1747 if not os.path.isfile(output_file): 1748 log.error(f"Editor returned success code: {status} but no output file was found: {output_file}") 1749 else: 1750 with open(output_file, "rb") as f: 1751 import_file_bytes = f.read() 1752 else: 1753 # File to memory and memory to memory, Editor wrote to a buffer, convert it to bytes 1754 import_file_bytes = utils.buffer_to_bytes( 1755 register_import.buffer, 1756 register_import.buffer_length 1757 ) 1758 1759 # Ensure memory allocated is not garbage collected 1760 content_management_policy, register_import, register_output, register_analysis 1761 1762 return import_file_bytes, analysis_report_bytes
Imports and analyses a file in a single session, returning both imported file bytes and analysis report bytes.
Args: input_file (Union[str, bytes, bytearray, io.BytesIO]): The input file path or bytes. output_file (Optional[str]): The output file path where the imported file will be written. output_analysis_report (Optional[str]): The output file path where the XML analysis report will be written. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply to the session. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: Tuple[Optional[bytes], Optional[bytes]]: A tuple of (import_file_bytes, analysis_report_bytes).
1764 def import_and_analyse_directory( 1765 self, 1766 input_directory: str, 1767 output_directory: Optional[str] = None, 1768 analysis_directory: Optional[str] = None, 1769 content_management_policy: Union[None, str, bytes, bytearray, io.BytesIO, "glasswall.content_management.policies.policy.Policy"] = None, 1770 raise_unsupported: bool = True, 1771 ): 1772 """ Recursively processes all files in a directory using import and analyse mode with the given content management policy. 1773 Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory. 1774 1775 Args: 1776 input_directory (str): The input directory containing export .zip files to process. 1777 output_directory (Optional[str]): The output directory for imported files. 1778 analysis_directory (Optional[str]): The output directory for XML analysis reports. 1779 content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. 1780 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 1781 1782 Returns: 1783 result_dict (dict): A dictionary mapping relative file paths to tuples of (import_file_bytes, analysis_report_bytes). 1784 """ 1785 result_dict = {} 1786 1787 for input_file in utils.list_file_paths(input_directory): 1788 relative_path = os.path.relpath(input_file, input_directory) 1789 # Remove .zip extension from relative_path 1790 if relative_path.endswith(".zip"): 1791 relative_path = os.path.splitext(relative_path)[0] 1792 output_file = None if output_directory is None else os.path.join(os.path.abspath(output_directory), relative_path) 1793 output_analysis_report = None if analysis_directory is None else os.path.join(os.path.abspath(analysis_directory), relative_path + ".xml") 1794 1795 import_file_bytes, analysis_report_bytes = self.import_and_analyse_file( 1796 input_file=input_file, 1797 output_file=output_file, 1798 output_analysis_report=output_analysis_report, 1799 content_management_policy=content_management_policy, 1800 raise_unsupported=raise_unsupported, 1801 ) 1802 1803 result_dict[relative_path] = (import_file_bytes, analysis_report_bytes) 1804 1805 return result_dict
Recursively processes all files in a directory using import and analyse mode with the given content management policy. Outputs are written to output_directory and analysis_directory maintaining the same structure as input_directory.
Args: input_directory (str): The input directory containing export .zip files to process. output_directory (Optional[str]): The output directory for imported files. analysis_directory (Optional[str]): The output directory for XML analysis reports. content_management_policy (Union[None, str, bytes, bytearray, io.BytesIO, glasswall.content_management.policies.policy.Policy], optional): The content management policy to apply. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: result_dict (dict): A dictionary mapping relative file paths to tuples of (import_file_bytes, analysis_report_bytes).
1846 @functools.lru_cache() 1847 def file_error_message(self, session: int) -> str: 1848 """ Retrieve the Glasswall Session Process error message. 1849 1850 Args: 1851 session (int): The session integer. 1852 1853 Returns: 1854 error_message (str): The Glasswall Session Process error message. 1855 """ 1856 # Validate arg types 1857 if not isinstance(session, int): 1858 raise TypeError(session) 1859 1860 result = self._GW2FileErrorMsg(session) 1861 1862 if result.status not in successes.success_codes: 1863 log.error(format_object(result)) 1864 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 1865 else: 1866 log.debug(format_object(result)) 1867 1868 return result.error_message
Retrieve the Glasswall Session Process error message.
Args: session (int): The session integer.
Returns: error_message (str): The Glasswall Session Process error message.
1870 def GW2GetFileType(self, session: int, file_type_id): 1871 """ Retrieve the file type as a string. 1872 1873 Args: 1874 session (int): The session integer. 1875 file_type_id (int): The file type id. 1876 1877 Returns: 1878 file_type (str): The formal file name for the corresponding file id. 1879 """ 1880 # Validate arg types 1881 if not isinstance(session, int): 1882 raise TypeError(session) 1883 1884 # API function declaration 1885 self.library.GW2GetFileType.argtypes = [ 1886 ct.c_size_t, 1887 ct.c_size_t, 1888 ct.POINTER(ct.c_size_t), 1889 ct.POINTER(ct.c_void_p) 1890 ] 1891 1892 # Variable initialisation 1893 ct_session = ct.c_size_t(session) 1894 ct_file_type = ct.c_size_t(file_type_id) 1895 ct_buffer_length = ct.c_size_t() 1896 ct_buffer = ct.c_void_p() 1897 1898 # API call 1899 status = self.library.GW2GetFileType( 1900 ct_session, 1901 ct_file_type, 1902 ct.byref(ct_buffer_length), 1903 ct.byref(ct_buffer) 1904 ) 1905 1906 if status not in successes.success_codes: 1907 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 1908 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1909 else: 1910 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 1911 1912 # Editor wrote to a buffer, convert it to bytes 1913 file_type_bytes = utils.buffer_to_bytes( 1914 ct_buffer, 1915 ct_buffer_length 1916 ) 1917 1918 file_type = file_type_bytes.decode() 1919 1920 return file_type
Retrieve the file type as a string.
Args: session (int): The session integer. file_type_id (int): The file type id.
Returns: file_type (str): The formal file name for the corresponding file id.
1922 def GW2GetFileTypeID(self, session: int, file_type_str): 1923 """ Retrieve the Glasswall file type id given a file type string. 1924 1925 Args: 1926 session (int): The session integer. 1927 file_type_str (str): The file type as a string. 1928 1929 Returns: 1930 file_type_id (str): The Glasswall file type id for the specified file type. 1931 """ 1932 # Validate arg types 1933 if not isinstance(session, int): 1934 raise TypeError(session) 1935 1936 # API function declaration 1937 self.library.GW2GetFileTypeID.argtypes = [ 1938 ct.c_size_t, 1939 ct.c_char_p, 1940 ct.POINTER(ct.c_size_t), 1941 ct.POINTER(ct.c_void_p) 1942 ] 1943 1944 # Variable initialisation 1945 ct_session = ct.c_size_t(session) 1946 ct_file_type = ct.c_char_p(file_type_str.encode('utf-8')) 1947 ct_buffer_length = ct.c_size_t() 1948 ct_buffer = ct.c_void_p() 1949 1950 # API call 1951 status = self.library.GW2GetFileTypeID( 1952 ct_session, 1953 ct_file_type, 1954 ct.byref(ct_buffer_length), 1955 ct.byref(ct_buffer) 1956 ) 1957 1958 if status not in successes.success_codes: 1959 log.error(f"\n\tsession: {session}\n\tstatus: {status}") 1960 raise errors.error_codes.get(status, errors.UnknownErrorCode)(status) 1961 else: 1962 log.debug(f"\n\tsession: {session}\n\tstatus: {status}") 1963 1964 # Editor wrote to a buffer, convert it to bytes 1965 file_type_bytes = utils.buffer_to_bytes( 1966 ct_buffer, 1967 ct_buffer_length 1968 ) 1969 1970 file_type_id = file_type_bytes.decode() 1971 1972 return file_type_id
Retrieve the Glasswall file type id given a file type string.
Args: session (int): The session integer. file_type_str (str): The file type as a string.
Returns: file_type_id (str): The Glasswall file type id for the specified file type.
1974 def get_file_type_info(self, file_type: Union[str, int]): 1975 """ Retrieve information about a file type based on its identifier. 1976 1977 Args: 1978 file_type (Union[str, int]): The file type identifier. This can be either a string representing a file 1979 extension (e.g. 'bmp') or an integer corresponding to a file type (e.g. 29). 1980 1981 Returns: 1982 - file_type_info (Union[int, str]): Depending on the input 'file_type': 1983 - If `file_type` is a string (e.g. 'bmp'): 1984 - If the file type is recognised, returns an integer corresponding to that file type. 1985 - If the file type is not recognised, returns 0. 1986 - If `file_type` is an integer (e.g. 29): 1987 - If the integer corresponds to a recognised file type, returns a more detailed string description 1988 of the file type (e.g. 'BMP Image'). 1989 - If the integer does not match any recognised file type, returns an empty string. 1990 """ 1991 # Validate arg types 1992 if not isinstance(file_type, (str, int)): 1993 raise TypeError(file_type) 1994 1995 with utils.CwdHandler(self.library_path): 1996 with self.new_session() as session: 1997 1998 if isinstance(file_type, int): 1999 file_type_info = self.GW2GetFileType(session, file_type) 2000 if isinstance(file_type, str): 2001 file_type_info = self.GW2GetFileTypeID(session, file_type) 2002 2003 return file_type_info
Retrieve information about a file type based on its identifier.
Args: file_type (Union[str, int]): The file type identifier. This can be either a string representing a file extension (e.g. 'bmp') or an integer corresponding to a file type (e.g. 29).
Returns:
- file_type_info (Union[int, str]): Depending on the input 'file_type':
- If file_type
is a string (e.g. 'bmp'):
- If the file type is recognised, returns an integer corresponding to that file type.
- If the file type is not recognised, returns 0.
- If file_type
is an integer (e.g. 29):
- If the integer corresponds to a recognised file type, returns a more detailed string description
of the file type (e.g. 'BMP Image').
- If the integer does not match any recognised file type, returns an empty string.
2005 @utils.deprecated_function(replacement_function=get_file_type_info) 2006 def get_file_info(self, *args, **kwargs): 2007 """ Deprecated in 1.0.6. Use get_file_type_info. """ 2008 pass
Deprecated in 1.0.6. Use get_file_type_info.
2039 def register_report_file(self, session: int, output_file: str): 2040 """ Register the report file path for the given session. 2041 2042 Args: 2043 session (int): The session integer. 2044 output_file (str): The file path of the report file. 2045 2046 Returns: 2047 gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'. 2048 """ 2049 # Validate arg types 2050 if not isinstance(session, int): 2051 raise TypeError(session) 2052 if not isinstance(output_file, (type(None), str)): 2053 raise TypeError(output_file) 2054 2055 result = self._GW2RegisterReportFile(session, output_file) 2056 2057 if result.status not in successes.success_codes: 2058 log.error(format_object(result)) 2059 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2060 else: 2061 log.debug(format_object(result)) 2062 2063 return result
Register the report file path for the given session.
Args: session (int): The session integer. output_file (str): The file path of the report file.
Returns: gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'output_file', 'status'.
2109 def get_id_info(self, issue_id: int, raise_unsupported: bool = True): 2110 """ Retrieves the group description for the given Issue ID. e.g. issue_id 96 returns "Document Processing Instances" 2111 2112 Args: 2113 issue_id (int): The issue id. 2114 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2115 2116 Returns: 2117 id_info (str): The group description for the given Issue ID. 2118 """ 2119 # Validate arg types 2120 if not isinstance(issue_id, int): 2121 raise TypeError(issue_id) 2122 2123 with utils.CwdHandler(self.library_path): 2124 with self.new_session() as session: 2125 result = self._GW2GetIdInfo(session, issue_id) 2126 2127 if result.status not in successes.success_codes: 2128 log.error(format_object(result)) 2129 if raise_unsupported: 2130 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2131 else: 2132 log.debug(format_object(result)) 2133 2134 return result.id_info
Retrieves the group description for the given Issue ID. e.g. issue_id 96 returns "Document Processing Instances"
Args: issue_id (int): The issue id. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: id_info (str): The group description for the given Issue ID.
2174 def get_all_id_info(self, output_file: Optional[str] = None, raise_unsupported: bool = True) -> str: 2175 """ Retrieves the XML containing all the Issue ID ranges with their group descriptions 2176 2177 Args: 2178 output_file (Optional[str]): The output file path where the analysis file will be written. 2179 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2180 2181 Returns: 2182 all_id_info (str): A string XML analysis report containing all id info. 2183 """ 2184 # Validate arg types 2185 if not isinstance(output_file, (type(None), str)): 2186 raise TypeError(output_file) 2187 if isinstance(output_file, str): 2188 output_file = os.path.abspath(output_file) 2189 2190 with utils.CwdHandler(self.library_path): 2191 with self.new_session() as session: 2192 result = self._GW2GetAllIdInfo(session) 2193 2194 if result.status not in successes.success_codes: 2195 log.error(format_object(result)) 2196 if raise_unsupported: 2197 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2198 else: 2199 log.debug(format_object(result)) 2200 2201 if isinstance(output_file, str): 2202 # GW2GetAllIdInfo is memory only, write to file 2203 # make directories that do not exist 2204 os.makedirs(os.path.dirname(output_file), exist_ok=True) 2205 with open(output_file, "w") as f: 2206 f.write(result.all_id_info) 2207 2208 return result.all_id_info
Retrieves the XML containing all the Issue ID ranges with their group descriptions
Args: output_file (Optional[str]): The output file path where the analysis file will be written. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: all_id_info (str): A string XML analysis report containing all id info.
2255 def file_session_status_message(self, session: int, raise_unsupported: bool = True) -> str: 2256 """ Retrieves the Glasswall session status message. Gives a high level indication of the processing that was carried out. 2257 2258 Args: 2259 session (int): The session integer. 2260 raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False. 2261 2262 Returns: 2263 result.message (str):The file session status message. 2264 """ 2265 # Validate arg types 2266 if not isinstance(session, int): 2267 raise TypeError(session) 2268 2269 result = self._GW2FileSessionStatus(session) 2270 2271 if result.status not in successes.success_codes: 2272 log.error(format_object(result)) 2273 if raise_unsupported: 2274 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2275 else: 2276 log.debug(format_object(result)) 2277 2278 return result.message
Retrieves the Glasswall session status message. Gives a high level indication of the processing that was carried out.
Args: session (int): The session integer. raise_unsupported (bool, optional): Default True. Raise exceptions when Glasswall encounters an error. Fail silently if False.
Returns: result.message (str):The file session status message.
2304 def licence_details(self): 2305 """ Returns a string containing details of the licence. 2306 2307 Returns: 2308 result (str): A string containing details of the licence. 2309 """ 2310 with self.new_session() as session: 2311 result = self._GW2LicenceDetails(session) 2312 2313 log.debug(f"\n\tsession: {session}\n\tGW2LicenceDetails: {result}") 2314 2315 return result
Returns a string containing details of the licence.
Returns: result (str): A string containing details of the licence.
2438 def register_licence(self, session: int, input_file: Union[str, bytes, bytearray, io.BytesIO]): 2439 """ Registers a "gwkey.lic" licence from file path or memory. 2440 2441 Args: 2442 session (int): The session integer. 2443 input_file (Union[str, bytes, bytearray, io.BytesIO]): The "gwkey.lic" licence. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object. 2444 2445 Returns: 2446 - result (glasswall.GwReturnObj): Depending on the input 'input_file': 2447 - If input_file is a str file path: 2448 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'. 2449 2450 - If input_file is a file in memory: 2451 - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'. 2452 """ 2453 if isinstance(input_file, str): 2454 if not os.path.isfile(input_file): 2455 raise FileNotFoundError(input_file) 2456 2457 input_file = os.path.abspath(input_file) 2458 2459 result = self._GW2RegisterLicenceFile(session, input_file) 2460 2461 elif isinstance(input_file, (bytes, bytearray, io.BytesIO,)): 2462 # Convert bytearray and io.BytesIO to bytes 2463 input_file = utils.as_bytes(input_file) 2464 2465 result = self._GW2RegisterLicenceMemory(session, input_file) 2466 2467 else: 2468 raise TypeError(input_file) 2469 2470 if result.status not in successes.success_codes: 2471 log.error(format_object(result)) 2472 raise errors.error_codes.get(result.status, errors.UnknownErrorCode)(result.status) 2473 else: 2474 log.debug(format_object(result)) 2475 2476 return result
Registers a "gwkey.lic" licence from file path or memory.
Args: session (int): The session integer. input_file (Union[str, bytes, bytearray, io.BytesIO]): The "gwkey.lic" licence. It can be provided as a file path (str), bytes, bytearray, or a BytesIO object.
Returns: - result (glasswall.GwReturnObj): Depending on the input 'input_file': - If input_file is a str file path: - gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'input_file', 'status'.
- If input_file is a file in memory:
- gw_return_object (glasswall.GwReturnObj): A GwReturnObj instance with the attributes 'session', 'buffer', 'buffer_length', 'status'.