# iwa-inspector source for `iwa-inspector` is a tool for inspecting iWork archives. covers the high-level structure of files. This inspector performs the top-level extraction of messages and parses using extracted Protocol Buffer definitions. ## Usage The sections are separated by a light gray horizontal line and a light gray vertical line. Panels can be resized by click-dragging the line. ### Selecting a File The file input element in the top-left corner of the page is limited to the IWA file types: `.numbers`, `.key`, and `.pages`. The site automatically fetches a sample file on load. ### Message Table The message table is shown just below the header bar. The column headers are: | name | description | |:----------|:----------------------| | `id` | Message ID | | `type` | Numeric Message Type | | `message` | Absolute Message Type | | `path` | Location of Message | The table can be sorted by clicking on the column headers. ### Searching for Messages The search text box in the top-right corner of the page is a plaintext search over the parsed messages. Searches will match field names, string values and UUID fields of message type `.TSP.UUID`. ### Selecting a Message When a row in the table is selected, the bottom-left panel will display the Protocol Buffers definition for the message and the bottom-right panel will display the parsed contents. ### Message Structure The bottom-right panel shows the following information: - "Message": parsed information following the message definition - "Metadata": parsed information from the message metadata - "Dependents": list of messages that list the current message as a dependency. Clicking on a message name in the inspector will show the message definition in the left pane. A "Return" link returns to the base message definition. Clicking on a `.TSP.Reference` ID will jump to the referenced message. ### Exporting Data Right-clicking a custom message type will show a context menu with options to copy the raw byte representation (array of numbers) or parsed object (JSON). ## Development ### Website `make dev` starts the dev server. `make build` generates the static site. `make init` installs dependencies. ### Protos and Messages `make deps` requires a SIP-disabled Mac with Keynote + Numbers + Pages. The dependencies were refreshed on 2024-12-18 against version 14.3 (7042.0.76). Due to breaking changes, Deno must be rolled back to version 1.46.3. The scripts are not compatible with Deno 2! 14.2 deprecated message 0x847 (`.TSWP.UpdateDateTimeFieldCommandArchive`). Curiously the message definition was retained in the protobuf definitions. The message type has been preserved in the messages list. #### Software License Agreements Before refreshing, each app must be launched once and the software license agreements must be accepted. In the 14.3 update, Keynote and Pages clearly state: > By clicking Continue you agree to the terms of the Keynote Software License Agreement #### Disabling SIP 1) Enter Recovery mode: On Intel Macs, shut down and restart while holding down Command+R keys. On Apple Silicon Macs, shut down and restart while holding down the Touch ID. It will display a message "Continue holding for startup options". Let go once the message changes to "Loading startup options" Select "Options" in the boot window and click the "Continue" button. 2) Open a terminal window (Utilities > Terminal) and run the following command: ``` csrutil disable ``` If there is no error, restart the machine. **Apple Silicon Extra Steps** If the command fails with a message like ``` csrutil: The OS environment does not allow changing security configuration options. Ensure that the system was booted into Recovery OS via the standard user action. ``` 3) Run the following command: ``` csrutil clear ``` 4) Open the "Startup Security Utility" (in the Utilities menu) 5) Click "Security Policy..." and select "Permissive Security". Click "OK". 6) Reboot into recovery mode (explained in Step 1) 7) Open a terminal window (Utilities > Terminal) and run: ``` csrutil disable ``` **Remember to re-enable SIP after updating messages!** #### Developer Tools error Note: Runs may fail with an error like ``` error: Uncaught (in promise) "Could not find map!" ``` Running the command a second time typically shows a popup: > Developer Tools Access needs to take control of another process for debugging to continue It will ask for Touch ID or password. After authorization, the build should run. ## Protocol Buffer Details Note that the `message` field is absolute. For example, `TSTArchives.proto` specifies the `.TST.TileStorage` as follows: ```proto package TST; message TileStorage { message Tile { required uint32 tileid = 1; required .TSP.Reference tile = 2; } repeated .TST.TileStorage.Tile tiles = 1; optional uint32 tile_size = 2; optional bool should_use_wide_rows = 3; } ``` The protobuf extractor rewrites the message names using the absolute form: ```proto message .TST.TileStorage { message Tile { required uint32 tileid = 1; required .TSP.Reference tile = 2; } repeated .TST.TileStorage.Tile tiles = 1; optional uint32 tile_size = 2; optional bool should_use_wide_rows = 3; } ```