subnoto-api-client 0.0.99__py3-none-manylinux2014_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (399) hide show
  1. oak_py_sdk/oak_client.so +0 -0
  2. subnoto_api_client/__init__.py +23 -0
  3. subnoto_api_client/client.py +155 -0
  4. subnoto_api_client/generated/__init__.py +8 -0
  5. subnoto_api_client/generated/api/__init__.py +1 -0
  6. subnoto_api_client/generated/api/contact/__init__.py +1 -0
  7. subnoto_api_client/generated/api/contact/post_public_contact_create.py +241 -0
  8. subnoto_api_client/generated/api/contact/post_public_contact_delete.py +241 -0
  9. subnoto_api_client/generated/api/contact/post_public_contact_get.py +241 -0
  10. subnoto_api_client/generated/api/contact/post_public_contact_list.py +241 -0
  11. subnoto_api_client/generated/api/contact/post_public_contact_update.py +241 -0
  12. subnoto_api_client/generated/api/envelope/__init__.py +1 -0
  13. subnoto_api_client/generated/api/envelope/post_public_envelope_add_blocks.py +243 -0
  14. subnoto_api_client/generated/api/envelope/post_public_envelope_add_recipients.py +253 -0
  15. subnoto_api_client/generated/api/envelope/post_public_envelope_complete_document_upload.py +257 -0
  16. subnoto_api_client/generated/api/envelope/post_public_envelope_create.py +253 -0
  17. subnoto_api_client/generated/api/envelope/post_public_envelope_create_from_template.py +257 -0
  18. subnoto_api_client/generated/api/envelope/post_public_envelope_delete.py +241 -0
  19. subnoto_api_client/generated/api/envelope/post_public_envelope_delete_blocks.py +253 -0
  20. subnoto_api_client/generated/api/envelope/post_public_envelope_delete_recipients.py +253 -0
  21. subnoto_api_client/generated/api/envelope/post_public_envelope_get.py +241 -0
  22. subnoto_api_client/generated/api/envelope/post_public_envelope_get_document.py +247 -0
  23. subnoto_api_client/generated/api/envelope/post_public_envelope_get_proof.py +237 -0
  24. subnoto_api_client/generated/api/envelope/post_public_envelope_list.py +227 -0
  25. subnoto_api_client/generated/api/envelope/post_public_envelope_send.py +241 -0
  26. subnoto_api_client/generated/api/envelope/post_public_envelope_sign.py +241 -0
  27. subnoto_api_client/generated/api/template/__init__.py +1 -0
  28. subnoto_api_client/generated/api/template/post_public_template_list.py +227 -0
  29. subnoto_api_client/generated/api/utils/__init__.py +1 -0
  30. subnoto_api_client/generated/api/utils/post_public_utils_whoami.py +227 -0
  31. subnoto_api_client/generated/api/workspace/__init__.py +1 -0
  32. subnoto_api_client/generated/api/workspace/post_public_workspace_list.py +227 -0
  33. subnoto_api_client/generated/client.py +282 -0
  34. subnoto_api_client/generated/errors.py +16 -0
  35. subnoto_api_client/generated/models/__init__.py +1271 -0
  36. subnoto_api_client/generated/models/post_public_contact_create_body.py +89 -0
  37. subnoto_api_client/generated/models/post_public_contact_create_body_contacts_item.py +88 -0
  38. subnoto_api_client/generated/models/post_public_contact_create_response_200.py +62 -0
  39. subnoto_api_client/generated/models/post_public_contact_create_response_200_contacts_item.py +80 -0
  40. subnoto_api_client/generated/models/post_public_contact_create_response_400.py +84 -0
  41. subnoto_api_client/generated/models/post_public_contact_create_response_400_error.py +70 -0
  42. subnoto_api_client/generated/models/post_public_contact_create_response_400_error_code.py +10 -0
  43. subnoto_api_client/generated/models/post_public_contact_create_response_401.py +84 -0
  44. subnoto_api_client/generated/models/post_public_contact_create_response_401_error.py +70 -0
  45. subnoto_api_client/generated/models/post_public_contact_create_response_401_error_code.py +10 -0
  46. subnoto_api_client/generated/models/post_public_contact_create_response_403.py +84 -0
  47. subnoto_api_client/generated/models/post_public_contact_create_response_403_error.py +70 -0
  48. subnoto_api_client/generated/models/post_public_contact_create_response_403_error_code.py +9 -0
  49. subnoto_api_client/generated/models/post_public_contact_create_response_500.py +84 -0
  50. subnoto_api_client/generated/models/post_public_contact_create_response_500_error.py +70 -0
  51. subnoto_api_client/generated/models/post_public_contact_create_response_500_error_code.py +9 -0
  52. subnoto_api_client/generated/models/post_public_contact_delete_body.py +69 -0
  53. subnoto_api_client/generated/models/post_public_contact_delete_response_200.py +24 -0
  54. subnoto_api_client/generated/models/post_public_contact_delete_response_400.py +84 -0
  55. subnoto_api_client/generated/models/post_public_contact_delete_response_400_error.py +70 -0
  56. subnoto_api_client/generated/models/post_public_contact_delete_response_400_error_code.py +10 -0
  57. subnoto_api_client/generated/models/post_public_contact_delete_response_401.py +84 -0
  58. subnoto_api_client/generated/models/post_public_contact_delete_response_401_error.py +70 -0
  59. subnoto_api_client/generated/models/post_public_contact_delete_response_401_error_code.py +10 -0
  60. subnoto_api_client/generated/models/post_public_contact_delete_response_403.py +84 -0
  61. subnoto_api_client/generated/models/post_public_contact_delete_response_403_error.py +70 -0
  62. subnoto_api_client/generated/models/post_public_contact_delete_response_403_error_code.py +9 -0
  63. subnoto_api_client/generated/models/post_public_contact_delete_response_500.py +84 -0
  64. subnoto_api_client/generated/models/post_public_contact_delete_response_500_error.py +70 -0
  65. subnoto_api_client/generated/models/post_public_contact_delete_response_500_error_code.py +9 -0
  66. subnoto_api_client/generated/models/post_public_contact_get_body.py +69 -0
  67. subnoto_api_client/generated/models/post_public_contact_get_response_200.py +52 -0
  68. subnoto_api_client/generated/models/post_public_contact_get_response_200_contact.py +80 -0
  69. subnoto_api_client/generated/models/post_public_contact_get_response_400.py +84 -0
  70. subnoto_api_client/generated/models/post_public_contact_get_response_400_error.py +70 -0
  71. subnoto_api_client/generated/models/post_public_contact_get_response_400_error_code.py +10 -0
  72. subnoto_api_client/generated/models/post_public_contact_get_response_401.py +84 -0
  73. subnoto_api_client/generated/models/post_public_contact_get_response_401_error.py +70 -0
  74. subnoto_api_client/generated/models/post_public_contact_get_response_401_error_code.py +10 -0
  75. subnoto_api_client/generated/models/post_public_contact_get_response_403.py +84 -0
  76. subnoto_api_client/generated/models/post_public_contact_get_response_403_error.py +70 -0
  77. subnoto_api_client/generated/models/post_public_contact_get_response_403_error_code.py +9 -0
  78. subnoto_api_client/generated/models/post_public_contact_get_response_500.py +84 -0
  79. subnoto_api_client/generated/models/post_public_contact_get_response_500_error.py +70 -0
  80. subnoto_api_client/generated/models/post_public_contact_get_response_500_error_code.py +9 -0
  81. subnoto_api_client/generated/models/post_public_contact_list_body.py +61 -0
  82. subnoto_api_client/generated/models/post_public_contact_list_response_200.py +62 -0
  83. subnoto_api_client/generated/models/post_public_contact_list_response_200_contacts_item.py +80 -0
  84. subnoto_api_client/generated/models/post_public_contact_list_response_400.py +84 -0
  85. subnoto_api_client/generated/models/post_public_contact_list_response_400_error.py +70 -0
  86. subnoto_api_client/generated/models/post_public_contact_list_response_400_error_code.py +9 -0
  87. subnoto_api_client/generated/models/post_public_contact_list_response_401.py +84 -0
  88. subnoto_api_client/generated/models/post_public_contact_list_response_401_error.py +70 -0
  89. subnoto_api_client/generated/models/post_public_contact_list_response_401_error_code.py +10 -0
  90. subnoto_api_client/generated/models/post_public_contact_list_response_403.py +84 -0
  91. subnoto_api_client/generated/models/post_public_contact_list_response_403_error.py +70 -0
  92. subnoto_api_client/generated/models/post_public_contact_list_response_403_error_code.py +9 -0
  93. subnoto_api_client/generated/models/post_public_contact_list_response_500.py +84 -0
  94. subnoto_api_client/generated/models/post_public_contact_list_response_500_error.py +70 -0
  95. subnoto_api_client/generated/models/post_public_contact_list_response_500_error_code.py +9 -0
  96. subnoto_api_client/generated/models/post_public_contact_update_body.py +79 -0
  97. subnoto_api_client/generated/models/post_public_contact_update_body_contact.py +91 -0
  98. subnoto_api_client/generated/models/post_public_contact_update_response_200.py +52 -0
  99. subnoto_api_client/generated/models/post_public_contact_update_response_200_contact.py +80 -0
  100. subnoto_api_client/generated/models/post_public_contact_update_response_400.py +84 -0
  101. subnoto_api_client/generated/models/post_public_contact_update_response_400_error.py +70 -0
  102. subnoto_api_client/generated/models/post_public_contact_update_response_400_error_code.py +11 -0
  103. subnoto_api_client/generated/models/post_public_contact_update_response_401.py +84 -0
  104. subnoto_api_client/generated/models/post_public_contact_update_response_401_error.py +70 -0
  105. subnoto_api_client/generated/models/post_public_contact_update_response_401_error_code.py +10 -0
  106. subnoto_api_client/generated/models/post_public_contact_update_response_403.py +84 -0
  107. subnoto_api_client/generated/models/post_public_contact_update_response_403_error.py +70 -0
  108. subnoto_api_client/generated/models/post_public_contact_update_response_403_error_code.py +9 -0
  109. subnoto_api_client/generated/models/post_public_contact_update_response_500.py +84 -0
  110. subnoto_api_client/generated/models/post_public_contact_update_response_500_error.py +70 -0
  111. subnoto_api_client/generated/models/post_public_contact_update_response_500_error_code.py +9 -0
  112. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body.py +174 -0
  113. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_0.py +153 -0
  114. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_0_templated_text.py +10 -0
  115. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_0_type.py +8 -0
  116. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_1.py +133 -0
  117. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_1_type.py +8 -0
  118. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_2.py +117 -0
  119. subnoto_api_client/generated/models/post_public_envelope_add_blocks_body_blocks_item_type_2_type.py +8 -0
  120. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_200.py +42 -0
  121. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_400.py +84 -0
  122. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_400_error.py +70 -0
  123. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_400_error_code.py +13 -0
  124. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_401.py +84 -0
  125. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_401_error.py +70 -0
  126. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_401_error_code.py +10 -0
  127. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_403.py +84 -0
  128. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_403_error.py +70 -0
  129. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_403_error_code.py +9 -0
  130. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_500.py +84 -0
  131. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_500_error.py +70 -0
  132. subnoto_api_client/generated/models/post_public_envelope_add_blocks_response_500_error_code.py +9 -0
  133. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body.py +171 -0
  134. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body_recipients_item_type_0.py +91 -0
  135. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body_recipients_item_type_0_type.py +8 -0
  136. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body_recipients_item_type_1.py +75 -0
  137. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body_recipients_item_type_1_type.py +8 -0
  138. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body_recipients_item_type_2.py +75 -0
  139. subnoto_api_client/generated/models/post_public_envelope_add_recipients_body_recipients_item_type_2_type.py +8 -0
  140. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_200.py +64 -0
  141. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_200_recipients_item.py +93 -0
  142. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_200_recipients_item_role.py +8 -0
  143. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_200_recipients_item_status.py +12 -0
  144. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_400.py +86 -0
  145. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_400_error.py +70 -0
  146. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_400_error_code.py +14 -0
  147. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_401.py +86 -0
  148. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_401_error.py +70 -0
  149. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_401_error_code.py +10 -0
  150. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_403.py +86 -0
  151. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_403_error.py +70 -0
  152. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_403_error_code.py +9 -0
  153. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_500.py +86 -0
  154. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_500_error.py +70 -0
  155. subnoto_api_client/generated/models/post_public_envelope_add_recipients_response_500_error_code.py +9 -0
  156. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_body.py +77 -0
  157. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_200.py +24 -0
  158. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_400.py +86 -0
  159. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_400_error.py +72 -0
  160. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_400_error_code.py +14 -0
  161. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_401.py +86 -0
  162. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_401_error.py +72 -0
  163. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_401_error_code.py +10 -0
  164. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_403.py +86 -0
  165. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_403_error.py +72 -0
  166. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_403_error_code.py +9 -0
  167. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_500.py +86 -0
  168. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_500_error.py +72 -0
  169. subnoto_api_client/generated/models/post_public_envelope_complete_document_upload_response_500_error_code.py +9 -0
  170. subnoto_api_client/generated/models/post_public_envelope_create_body.py +81 -0
  171. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body.py +170 -0
  172. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body_recipients_item_type_0.py +99 -0
  173. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body_recipients_item_type_0_type.py +8 -0
  174. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body_recipients_item_type_1.py +83 -0
  175. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body_recipients_item_type_1_type.py +8 -0
  176. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body_recipients_item_type_2.py +83 -0
  177. subnoto_api_client/generated/models/post_public_envelope_create_from_template_body_recipients_item_type_2_type.py +8 -0
  178. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_200.py +50 -0
  179. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_400.py +86 -0
  180. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_400_error.py +70 -0
  181. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_400_error_code.py +13 -0
  182. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_401.py +86 -0
  183. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_401_error.py +70 -0
  184. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_401_error_code.py +10 -0
  185. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_403.py +86 -0
  186. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_403_error.py +70 -0
  187. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_403_error_code.py +9 -0
  188. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_500.py +86 -0
  189. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_500_error.py +70 -0
  190. subnoto_api_client/generated/models/post_public_envelope_create_from_template_response_500_error_code.py +9 -0
  191. subnoto_api_client/generated/models/post_public_envelope_create_response_200.py +95 -0
  192. subnoto_api_client/generated/models/post_public_envelope_create_response_200_presigned_s3_params.py +63 -0
  193. subnoto_api_client/generated/models/post_public_envelope_create_response_200_presigned_s3_params_fields.py +99 -0
  194. subnoto_api_client/generated/models/post_public_envelope_create_response_400.py +84 -0
  195. subnoto_api_client/generated/models/post_public_envelope_create_response_400_error.py +70 -0
  196. subnoto_api_client/generated/models/post_public_envelope_create_response_400_error_code.py +12 -0
  197. subnoto_api_client/generated/models/post_public_envelope_create_response_401.py +84 -0
  198. subnoto_api_client/generated/models/post_public_envelope_create_response_401_error.py +70 -0
  199. subnoto_api_client/generated/models/post_public_envelope_create_response_401_error_code.py +10 -0
  200. subnoto_api_client/generated/models/post_public_envelope_create_response_403.py +84 -0
  201. subnoto_api_client/generated/models/post_public_envelope_create_response_403_error.py +70 -0
  202. subnoto_api_client/generated/models/post_public_envelope_create_response_403_error_code.py +9 -0
  203. subnoto_api_client/generated/models/post_public_envelope_create_response_500.py +84 -0
  204. subnoto_api_client/generated/models/post_public_envelope_create_response_500_error.py +70 -0
  205. subnoto_api_client/generated/models/post_public_envelope_create_response_500_error_code.py +9 -0
  206. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_body.py +85 -0
  207. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_200.py +42 -0
  208. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_400.py +84 -0
  209. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_400_error.py +70 -0
  210. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_400_error_code.py +12 -0
  211. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_401.py +84 -0
  212. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_401_error.py +70 -0
  213. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_401_error_code.py +10 -0
  214. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_403.py +84 -0
  215. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_403_error.py +70 -0
  216. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_403_error_code.py +9 -0
  217. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_500.py +84 -0
  218. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_500_error.py +70 -0
  219. subnoto_api_client/generated/models/post_public_envelope_delete_blocks_response_500_error_code.py +9 -0
  220. subnoto_api_client/generated/models/post_public_envelope_delete_body.py +69 -0
  221. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_body.py +99 -0
  222. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_body_recipients_item.py +61 -0
  223. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_200.py +24 -0
  224. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_400.py +86 -0
  225. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_400_error.py +70 -0
  226. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_400_error_code.py +12 -0
  227. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_401.py +86 -0
  228. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_401_error.py +70 -0
  229. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_401_error_code.py +10 -0
  230. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_403.py +86 -0
  231. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_403_error.py +70 -0
  232. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_403_error_code.py +9 -0
  233. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_500.py +86 -0
  234. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_500_error.py +70 -0
  235. subnoto_api_client/generated/models/post_public_envelope_delete_recipients_response_500_error_code.py +9 -0
  236. subnoto_api_client/generated/models/post_public_envelope_delete_response_200.py +24 -0
  237. subnoto_api_client/generated/models/post_public_envelope_delete_response_400.py +84 -0
  238. subnoto_api_client/generated/models/post_public_envelope_delete_response_400_error.py +70 -0
  239. subnoto_api_client/generated/models/post_public_envelope_delete_response_400_error_code.py +10 -0
  240. subnoto_api_client/generated/models/post_public_envelope_delete_response_401.py +84 -0
  241. subnoto_api_client/generated/models/post_public_envelope_delete_response_401_error.py +70 -0
  242. subnoto_api_client/generated/models/post_public_envelope_delete_response_401_error_code.py +10 -0
  243. subnoto_api_client/generated/models/post_public_envelope_delete_response_403.py +84 -0
  244. subnoto_api_client/generated/models/post_public_envelope_delete_response_403_error.py +70 -0
  245. subnoto_api_client/generated/models/post_public_envelope_delete_response_403_error_code.py +9 -0
  246. subnoto_api_client/generated/models/post_public_envelope_delete_response_500.py +84 -0
  247. subnoto_api_client/generated/models/post_public_envelope_delete_response_500_error.py +70 -0
  248. subnoto_api_client/generated/models/post_public_envelope_delete_response_500_error_code.py +9 -0
  249. subnoto_api_client/generated/models/post_public_envelope_get_body.py +69 -0
  250. subnoto_api_client/generated/models/post_public_envelope_get_document_body.py +77 -0
  251. subnoto_api_client/generated/models/post_public_envelope_get_document_response_400.py +84 -0
  252. subnoto_api_client/generated/models/post_public_envelope_get_document_response_400_error.py +70 -0
  253. subnoto_api_client/generated/models/post_public_envelope_get_document_response_400_error_code.py +13 -0
  254. subnoto_api_client/generated/models/post_public_envelope_get_document_response_401.py +84 -0
  255. subnoto_api_client/generated/models/post_public_envelope_get_document_response_401_error.py +70 -0
  256. subnoto_api_client/generated/models/post_public_envelope_get_document_response_401_error_code.py +10 -0
  257. subnoto_api_client/generated/models/post_public_envelope_get_document_response_403.py +84 -0
  258. subnoto_api_client/generated/models/post_public_envelope_get_document_response_403_error.py +70 -0
  259. subnoto_api_client/generated/models/post_public_envelope_get_document_response_403_error_code.py +9 -0
  260. subnoto_api_client/generated/models/post_public_envelope_get_document_response_500.py +84 -0
  261. subnoto_api_client/generated/models/post_public_envelope_get_document_response_500_error.py +70 -0
  262. subnoto_api_client/generated/models/post_public_envelope_get_document_response_500_error_code.py +9 -0
  263. subnoto_api_client/generated/models/post_public_envelope_get_proof_body.py +69 -0
  264. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_400.py +84 -0
  265. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_400_error.py +70 -0
  266. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_400_error_code.py +13 -0
  267. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_401.py +84 -0
  268. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_401_error.py +70 -0
  269. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_401_error_code.py +10 -0
  270. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_403.py +84 -0
  271. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_403_error.py +70 -0
  272. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_403_error_code.py +9 -0
  273. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_500.py +84 -0
  274. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_500_error.py +70 -0
  275. subnoto_api_client/generated/models/post_public_envelope_get_proof_response_500_error_code.py +9 -0
  276. subnoto_api_client/generated/models/post_public_envelope_get_response_200.py +170 -0
  277. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item.py +106 -0
  278. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks.py +162 -0
  279. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_0.py +236 -0
  280. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_0_color.py +15 -0
  281. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_0_label_icon.py +14 -0
  282. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_0_templated_text.py +12 -0
  283. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_0_type.py +10 -0
  284. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_1.py +207 -0
  285. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_1_color.py +15 -0
  286. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_1_label_icon.py +14 -0
  287. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_1_type.py +10 -0
  288. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_2.py +191 -0
  289. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_2_color.py +15 -0
  290. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_2_label_icon.py +14 -0
  291. subnoto_api_client/generated/models/post_public_envelope_get_response_200_documents_item_blocks_additional_property_item_type_2_type.py +10 -0
  292. subnoto_api_client/generated/models/post_public_envelope_get_response_200_metrics.py +66 -0
  293. subnoto_api_client/generated/models/post_public_envelope_get_response_200_owner.py +93 -0
  294. subnoto_api_client/generated/models/post_public_envelope_get_response_200_sender.py +51 -0
  295. subnoto_api_client/generated/models/post_public_envelope_get_response_200_status.py +14 -0
  296. subnoto_api_client/generated/models/post_public_envelope_get_response_400.py +84 -0
  297. subnoto_api_client/generated/models/post_public_envelope_get_response_400_error.py +70 -0
  298. subnoto_api_client/generated/models/post_public_envelope_get_response_400_error_code.py +10 -0
  299. subnoto_api_client/generated/models/post_public_envelope_get_response_401.py +84 -0
  300. subnoto_api_client/generated/models/post_public_envelope_get_response_401_error.py +70 -0
  301. subnoto_api_client/generated/models/post_public_envelope_get_response_401_error_code.py +10 -0
  302. subnoto_api_client/generated/models/post_public_envelope_get_response_403.py +84 -0
  303. subnoto_api_client/generated/models/post_public_envelope_get_response_403_error.py +70 -0
  304. subnoto_api_client/generated/models/post_public_envelope_get_response_403_error_code.py +9 -0
  305. subnoto_api_client/generated/models/post_public_envelope_get_response_500.py +84 -0
  306. subnoto_api_client/generated/models/post_public_envelope_get_response_500_error.py +70 -0
  307. subnoto_api_client/generated/models/post_public_envelope_get_response_500_error_code.py +9 -0
  308. subnoto_api_client/generated/models/post_public_envelope_list_body.py +82 -0
  309. subnoto_api_client/generated/models/post_public_envelope_list_response_200.py +62 -0
  310. subnoto_api_client/generated/models/post_public_envelope_list_response_200_envelopes_item.py +144 -0
  311. subnoto_api_client/generated/models/post_public_envelope_list_response_200_envelopes_item_metrics.py +67 -0
  312. subnoto_api_client/generated/models/post_public_envelope_list_response_200_envelopes_item_owner.py +79 -0
  313. subnoto_api_client/generated/models/post_public_envelope_list_response_200_envelopes_item_status.py +14 -0
  314. subnoto_api_client/generated/models/post_public_envelope_list_response_401.py +84 -0
  315. subnoto_api_client/generated/models/post_public_envelope_list_response_401_error.py +70 -0
  316. subnoto_api_client/generated/models/post_public_envelope_list_response_401_error_code.py +10 -0
  317. subnoto_api_client/generated/models/post_public_envelope_list_response_403.py +84 -0
  318. subnoto_api_client/generated/models/post_public_envelope_list_response_403_error.py +70 -0
  319. subnoto_api_client/generated/models/post_public_envelope_list_response_403_error_code.py +9 -0
  320. subnoto_api_client/generated/models/post_public_envelope_list_response_500.py +84 -0
  321. subnoto_api_client/generated/models/post_public_envelope_list_response_500_error.py +70 -0
  322. subnoto_api_client/generated/models/post_public_envelope_list_response_500_error_code.py +9 -0
  323. subnoto_api_client/generated/models/post_public_envelope_send_body.py +90 -0
  324. subnoto_api_client/generated/models/post_public_envelope_send_response_200.py +24 -0
  325. subnoto_api_client/generated/models/post_public_envelope_send_response_400.py +84 -0
  326. subnoto_api_client/generated/models/post_public_envelope_send_response_400_error.py +70 -0
  327. subnoto_api_client/generated/models/post_public_envelope_send_response_400_error_code.py +15 -0
  328. subnoto_api_client/generated/models/post_public_envelope_send_response_401.py +84 -0
  329. subnoto_api_client/generated/models/post_public_envelope_send_response_401_error.py +70 -0
  330. subnoto_api_client/generated/models/post_public_envelope_send_response_401_error_code.py +10 -0
  331. subnoto_api_client/generated/models/post_public_envelope_send_response_403.py +84 -0
  332. subnoto_api_client/generated/models/post_public_envelope_send_response_403_error.py +70 -0
  333. subnoto_api_client/generated/models/post_public_envelope_send_response_403_error_code.py +9 -0
  334. subnoto_api_client/generated/models/post_public_envelope_send_response_500.py +84 -0
  335. subnoto_api_client/generated/models/post_public_envelope_send_response_500_error.py +70 -0
  336. subnoto_api_client/generated/models/post_public_envelope_send_response_500_error_code.py +9 -0
  337. subnoto_api_client/generated/models/post_public_envelope_sign_body.py +88 -0
  338. subnoto_api_client/generated/models/post_public_envelope_sign_response_200.py +58 -0
  339. subnoto_api_client/generated/models/post_public_envelope_sign_response_400.py +84 -0
  340. subnoto_api_client/generated/models/post_public_envelope_sign_response_400_error.py +70 -0
  341. subnoto_api_client/generated/models/post_public_envelope_sign_response_400_error_code.py +16 -0
  342. subnoto_api_client/generated/models/post_public_envelope_sign_response_401.py +84 -0
  343. subnoto_api_client/generated/models/post_public_envelope_sign_response_401_error.py +70 -0
  344. subnoto_api_client/generated/models/post_public_envelope_sign_response_401_error_code.py +10 -0
  345. subnoto_api_client/generated/models/post_public_envelope_sign_response_403.py +84 -0
  346. subnoto_api_client/generated/models/post_public_envelope_sign_response_403_error.py +70 -0
  347. subnoto_api_client/generated/models/post_public_envelope_sign_response_403_error_code.py +9 -0
  348. subnoto_api_client/generated/models/post_public_envelope_sign_response_500.py +84 -0
  349. subnoto_api_client/generated/models/post_public_envelope_sign_response_500_error.py +70 -0
  350. subnoto_api_client/generated/models/post_public_envelope_sign_response_500_error_code.py +9 -0
  351. subnoto_api_client/generated/models/post_public_template_list_body.py +52 -0
  352. subnoto_api_client/generated/models/post_public_template_list_response_200.py +62 -0
  353. subnoto_api_client/generated/models/post_public_template_list_response_200_templates_item.py +174 -0
  354. subnoto_api_client/generated/models/post_public_template_list_response_200_templates_item_documents_item.py +50 -0
  355. subnoto_api_client/generated/models/post_public_template_list_response_200_templates_item_owner.py +79 -0
  356. subnoto_api_client/generated/models/post_public_template_list_response_200_templates_item_recipients_item.py +42 -0
  357. subnoto_api_client/generated/models/post_public_template_list_response_200_templates_item_status.py +11 -0
  358. subnoto_api_client/generated/models/post_public_template_list_response_401.py +84 -0
  359. subnoto_api_client/generated/models/post_public_template_list_response_401_error.py +70 -0
  360. subnoto_api_client/generated/models/post_public_template_list_response_401_error_code.py +10 -0
  361. subnoto_api_client/generated/models/post_public_template_list_response_403.py +84 -0
  362. subnoto_api_client/generated/models/post_public_template_list_response_403_error.py +70 -0
  363. subnoto_api_client/generated/models/post_public_template_list_response_403_error_code.py +9 -0
  364. subnoto_api_client/generated/models/post_public_template_list_response_500.py +84 -0
  365. subnoto_api_client/generated/models/post_public_template_list_response_500_error.py +70 -0
  366. subnoto_api_client/generated/models/post_public_template_list_response_500_error_code.py +9 -0
  367. subnoto_api_client/generated/models/post_public_utils_whoami_body.py +46 -0
  368. subnoto_api_client/generated/models/post_public_utils_whoami_response_200.py +74 -0
  369. subnoto_api_client/generated/models/post_public_utils_whoami_response_401.py +84 -0
  370. subnoto_api_client/generated/models/post_public_utils_whoami_response_401_error.py +70 -0
  371. subnoto_api_client/generated/models/post_public_utils_whoami_response_401_error_code.py +10 -0
  372. subnoto_api_client/generated/models/post_public_utils_whoami_response_403.py +84 -0
  373. subnoto_api_client/generated/models/post_public_utils_whoami_response_403_error.py +70 -0
  374. subnoto_api_client/generated/models/post_public_utils_whoami_response_403_error_code.py +9 -0
  375. subnoto_api_client/generated/models/post_public_utils_whoami_response_500.py +84 -0
  376. subnoto_api_client/generated/models/post_public_utils_whoami_response_500_error.py +70 -0
  377. subnoto_api_client/generated/models/post_public_utils_whoami_response_500_error_code.py +9 -0
  378. subnoto_api_client/generated/models/post_public_workspace_list_body.py +46 -0
  379. subnoto_api_client/generated/models/post_public_workspace_list_response_200.py +64 -0
  380. subnoto_api_client/generated/models/post_public_workspace_list_response_200_workspaces_item.py +74 -0
  381. subnoto_api_client/generated/models/post_public_workspace_list_response_401.py +84 -0
  382. subnoto_api_client/generated/models/post_public_workspace_list_response_401_error.py +70 -0
  383. subnoto_api_client/generated/models/post_public_workspace_list_response_401_error_code.py +10 -0
  384. subnoto_api_client/generated/models/post_public_workspace_list_response_403.py +84 -0
  385. subnoto_api_client/generated/models/post_public_workspace_list_response_403_error.py +70 -0
  386. subnoto_api_client/generated/models/post_public_workspace_list_response_403_error_code.py +9 -0
  387. subnoto_api_client/generated/models/post_public_workspace_list_response_500.py +84 -0
  388. subnoto_api_client/generated/models/post_public_workspace_list_response_500_error.py +70 -0
  389. subnoto_api_client/generated/models/post_public_workspace_list_response_500_error_code.py +9 -0
  390. subnoto_api_client/generated/types.py +54 -0
  391. subnoto_api_client/middleware/__init__.py +15 -0
  392. subnoto_api_client/middleware/signature_utils.py +128 -0
  393. subnoto_api_client/middleware/tunnel.py +119 -0
  394. subnoto_api_client/session.py +239 -0
  395. subnoto_api_client/transport.py +156 -0
  396. subnoto_api_client/types.py +43 -0
  397. subnoto_api_client-0.0.99.dist-info/METADATA +81 -0
  398. subnoto_api_client-0.0.99.dist-info/RECORD +399 -0
  399. subnoto_api_client-0.0.99.dist-info/WHEEL +4 -0
@@ -0,0 +1,70 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Any, TypeVar
5
+
6
+ from attrs import define as _attrs_define
7
+
8
+ from ..models.post_public_workspace_list_response_500_error_code import (
9
+ PostPublicWorkspaceListResponse500ErrorCode,
10
+ )
11
+
12
+ T = TypeVar("T", bound="PostPublicWorkspaceListResponse500Error")
13
+
14
+
15
+ @_attrs_define
16
+ class PostPublicWorkspaceListResponse500Error:
17
+ """
18
+ Attributes:
19
+ code (PostPublicWorkspaceListResponse500ErrorCode): The error code
20
+ message (str): The error message
21
+ suggestion (str): A suggestion to resolve the error
22
+ documentation_url (str): A URL to the documentation
23
+ """
24
+
25
+ code: PostPublicWorkspaceListResponse500ErrorCode
26
+ message: str
27
+ suggestion: str
28
+ documentation_url: str
29
+
30
+ def to_dict(self) -> dict[str, Any]:
31
+ code = self.code.value
32
+
33
+ message = self.message
34
+
35
+ suggestion = self.suggestion
36
+
37
+ documentation_url = self.documentation_url
38
+
39
+ field_dict: dict[str, Any] = {}
40
+
41
+ field_dict.update(
42
+ {
43
+ "code": code,
44
+ "message": message,
45
+ "suggestion": suggestion,
46
+ "documentationUrl": documentation_url,
47
+ }
48
+ )
49
+
50
+ return field_dict
51
+
52
+ @classmethod
53
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
54
+ d = dict(src_dict)
55
+ code = PostPublicWorkspaceListResponse500ErrorCode(d.pop("code"))
56
+
57
+ message = d.pop("message")
58
+
59
+ suggestion = d.pop("suggestion")
60
+
61
+ documentation_url = d.pop("documentationUrl")
62
+
63
+ post_public_workspace_list_response_500_error = cls(
64
+ code=code,
65
+ message=message,
66
+ suggestion=suggestion,
67
+ documentation_url=documentation_url,
68
+ )
69
+
70
+ return post_public_workspace_list_response_500_error
@@ -0,0 +1,9 @@
1
+ from enum import Enum
2
+
3
+
4
+ class PostPublicWorkspaceListResponse500ErrorCode(str, Enum):
5
+ INTERNAL_SERVER_ERROR = "INTERNAL_SERVER_ERROR"
6
+ INVALID_REQUEST_FORMAT = "INVALID_REQUEST_FORMAT"
7
+
8
+ def __str__(self) -> str:
9
+ return str(self.value)
@@ -0,0 +1,54 @@
1
+ """Contains some shared types for properties"""
2
+
3
+ from collections.abc import Mapping, MutableMapping
4
+ from http import HTTPStatus
5
+ from typing import IO, BinaryIO, Generic, Literal, TypeVar
6
+
7
+ from attrs import define
8
+
9
+
10
+ class Unset:
11
+ def __bool__(self) -> Literal[False]:
12
+ return False
13
+
14
+
15
+ UNSET: Unset = Unset()
16
+
17
+ # The types that `httpx.Client(files=)` can accept, copied from that library.
18
+ FileContent = IO[bytes] | bytes | str
19
+ FileTypes = (
20
+ # (filename, file (or bytes), content_type)
21
+ tuple[str | None, FileContent, str | None]
22
+ # (filename, file (or bytes), content_type, headers)
23
+ | tuple[str | None, FileContent, str | None, Mapping[str, str]]
24
+ )
25
+ RequestFiles = list[tuple[str, FileTypes]]
26
+
27
+
28
+ @define
29
+ class File:
30
+ """Contains information for file uploads"""
31
+
32
+ payload: BinaryIO
33
+ file_name: str | None = None
34
+ mime_type: str | None = None
35
+
36
+ def to_tuple(self) -> FileTypes:
37
+ """Return a tuple representation that httpx will accept for multipart/form-data"""
38
+ return self.file_name, self.payload, self.mime_type
39
+
40
+
41
+ T = TypeVar("T")
42
+
43
+
44
+ @define
45
+ class Response(Generic[T]):
46
+ """A response from an endpoint"""
47
+
48
+ status_code: HTTPStatus
49
+ content: bytes
50
+ headers: MutableMapping[str, str]
51
+ parsed: T | None
52
+
53
+
54
+ __all__ = ["UNSET", "File", "FileTypes", "RequestFiles", "Response", "Unset"]
@@ -0,0 +1,15 @@
1
+ # Copyright 2025 Subnoto
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
@@ -0,0 +1,128 @@
1
+ # Copyright 2025 Subnoto
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ """
17
+ HTTP signature utilities for signing requests (RFC 9421)
18
+
19
+ Uses http-message-signatures library (RFC 9421 implementation)
20
+ """
21
+
22
+ import base64
23
+ import hashlib
24
+ import time
25
+ from typing import Dict
26
+
27
+ from http_message_signatures import HTTPMessageSigner, HTTPSignatureKeyResolver, algorithms
28
+ from http_message_signatures import http_sfv
29
+
30
+
31
+ class SubnotoHTTPSignatureKeyResolver(HTTPSignatureKeyResolver):
32
+ """Key resolver for Subnoto API signatures"""
33
+
34
+ def __init__(self, access_key: str, secret_key: str):
35
+ self.access_key = access_key
36
+ self.secret_key_bytes = bytes.fromhex(secret_key)
37
+
38
+ def resolve_private_key(self, key_id: str):
39
+ if key_id == self.access_key:
40
+ return self.secret_key_bytes
41
+ return None
42
+
43
+
44
+ def sign_request_headers(
45
+ url: str,
46
+ method: str,
47
+ body_content: bytes,
48
+ access_key: str,
49
+ secret_key: str,
50
+ existing_headers: Dict[str, str]
51
+ ) -> Dict[str, str]:
52
+ """
53
+ Generate HTTP signature headers for a request using RFC 9421
54
+
55
+ Returns a dictionary of headers to add to the request, including:
56
+ - X-Timestamp
57
+ - Digest (legacy)
58
+ - Content-Digest (RFC 9530)
59
+ - Content-Type
60
+ - Content-Length
61
+ - Signature-Input
62
+ - Signature
63
+ """
64
+ # Generate digests
65
+ sha256_hash = hashlib.sha256(body_content).digest()
66
+ digest_base64 = base64.b64encode(sha256_hash).decode("utf-8")
67
+
68
+ # Legacy Digest header (for compatibility)
69
+ digest = f"SHA-256={digest_base64}"
70
+
71
+ # RFC 9530 Content-Digest header (using http_sfv for proper formatting)
72
+ content_digest_dict = http_sfv.Dictionary({"sha-256": sha256_hash})
73
+ content_digest = str(content_digest_dict)
74
+
75
+ # Timestamp
76
+ timestamp = str(int(time.time() * 1000))
77
+
78
+ # Get content type from existing headers (case-insensitive)
79
+ content_type = "application/json"
80
+ for k, v in existing_headers.items():
81
+ if k.lower() == "content-type":
82
+ content_type = v
83
+ break
84
+
85
+ # Build headers dict
86
+ headers = {
87
+ "X-Timestamp": timestamp,
88
+ "Digest": digest,
89
+ "Content-Digest": content_digest,
90
+ "Content-Type": content_type,
91
+ "Content-Length": str(len(body_content)),
92
+ }
93
+
94
+ # Simple object for the signing library (modifies headers in place)
95
+ class SignableRequest:
96
+ pass
97
+
98
+ request = SignableRequest()
99
+ request.method = method
100
+ request.url = url
101
+ request.headers = headers
102
+ request.body = body_content
103
+
104
+ # Sign the request
105
+ key_resolver = SubnotoHTTPSignatureKeyResolver(access_key, secret_key)
106
+ signer = HTTPMessageSigner(
107
+ signature_algorithm=algorithms.HMAC_SHA256,
108
+ key_resolver=key_resolver
109
+ )
110
+ signer.sign(
111
+ request,
112
+ key_id=access_key,
113
+ covered_component_ids=(
114
+ "x-timestamp",
115
+ "@authority",
116
+ "content-type",
117
+ "content-digest",
118
+ "content-length"
119
+ )
120
+ )
121
+
122
+ # Replace "pyhms" label with "team"
123
+ if "Signature" in headers:
124
+ headers["Signature"] = headers["Signature"].replace("pyhms=", "team=")
125
+ if "Signature-Input" in headers:
126
+ headers["Signature-Input"] = headers["Signature-Input"].replace("pyhms=", "team=")
127
+
128
+ return headers
@@ -0,0 +1,119 @@
1
+ # Copyright 2025 Subnoto
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ from typing import TYPE_CHECKING
17
+
18
+ import httpx
19
+
20
+ from ..types import SubnotoError
21
+
22
+ if TYPE_CHECKING:
23
+ from ..session import SessionManager
24
+
25
+
26
+ def create_tunnel_middleware(session_manager: "SessionManager"):
27
+ """Create tunnel encryption/decryption middleware"""
28
+
29
+ async def encrypt_request(request: "httpx.Request") -> None:
30
+ """Encrypt request body before sending"""
31
+ url = str(request.url)
32
+
33
+ # Skip if not targeting the enclave API
34
+ if "/tunnel/" not in url and "/public/" not in url:
35
+ return
36
+
37
+ # Skip tunnel handshake endpoint itself
38
+ if "/tunnel/session" in url:
39
+ return
40
+
41
+ # Ensure session is established
42
+ await session_manager.ensure_session()
43
+
44
+ # Get request body
45
+ body_content = request.content
46
+ if not body_content or len(body_content) == 0:
47
+ raise SubnotoError("EMPTY_REQUEST_BODY")
48
+
49
+ # Encrypt the request body
50
+ encrypted_message = session_manager.encrypt_request(body_content)
51
+
52
+ if not encrypted_message or len(encrypted_message) == 0:
53
+ raise SubnotoError("Empty encrypted message")
54
+
55
+ # Get session ID
56
+ session_id = session_manager.get_session_id()
57
+ if not session_id:
58
+ raise SubnotoError("Session ID not available")
59
+
60
+ # Update headers
61
+ request.headers["X-Session-Id"] = session_id
62
+ request.headers["Content-Type"] = "application/octet-stream"
63
+
64
+ # Remove old Content-Length so httpx recalculates it
65
+ if "Content-Length" in request.headers:
66
+ del request.headers["Content-Length"]
67
+
68
+ # Add cookies if available
69
+ cookies = session_manager._get_cookies_for_request(url)
70
+ if cookies:
71
+ request.headers["Cookie"] = cookies
72
+
73
+ # Update request content using stream - httpx handles Content-Length
74
+ request.stream = httpx.ByteStream(encrypted_message)
75
+
76
+ async def decrypt_response(response: "httpx.Response") -> None:
77
+ """Decrypt response body after receiving"""
78
+ url = str(response.request.url)
79
+
80
+ # Skip if not targeting the enclave API
81
+ if "/tunnel/" not in url and "/public/" not in url:
82
+ return
83
+
84
+ # Skip tunnel handshake endpoint itself
85
+ if "/tunnel/session" in url:
86
+ return
87
+
88
+ # Check if response is encrypted
89
+ is_encrypted = (
90
+ response.headers.get("x-subnoto-encrypted-response") == "true"
91
+ and response.headers.get("content-type") == "application/octet-stream"
92
+ )
93
+
94
+ if not is_encrypted:
95
+ # Return as-is if not encrypted
96
+ return
97
+
98
+ # Get encrypted data
99
+ encrypted_data = response.content
100
+
101
+ if len(encrypted_data) == 0:
102
+ raise SubnotoError("Empty encrypted response")
103
+
104
+ # Decrypt the response
105
+ decrypted_data = session_manager.decrypt_response(encrypted_data)
106
+
107
+ # Replace response content with decrypted data
108
+ # Note: httpx.Response is immutable, so we need to modify the stream
109
+ # This is a workaround - in practice, we may need to return a new response
110
+ response._content = decrypted_data
111
+ response.headers["Content-Type"] = "application/json"
112
+ if "x-subnoto-encrypted-response" in response.headers:
113
+ del response.headers["x-subnoto-encrypted-response"]
114
+
115
+ return {
116
+ "request": encrypt_request,
117
+ "response": decrypt_response
118
+ }
119
+
@@ -0,0 +1,239 @@
1
+ # Copyright 2025 Subnoto
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ import asyncio
17
+ from http.cookiejar import Cookie, CookieJar
18
+ from typing import Optional
19
+ from urllib.parse import urlparse
20
+
21
+ import httpx
22
+
23
+ try:
24
+ from oak_py_sdk.oak_client import PyClientSession
25
+ except ImportError as e:
26
+ raise ImportError(
27
+ f"oak_client module not found: {e}\n"
28
+ "Make sure oak_py_sdk is built:\n"
29
+ " eval \"$(direnv export bash)\" && bazel build //oak_py_sdk:oak_client"
30
+ )
31
+
32
+ from .types import SubnotoConfig, SubnotoError
33
+
34
+
35
+ class SessionManager:
36
+ """Manages Oak session encryption using PyO3 bindings from oak_py_sdk"""
37
+
38
+ def __init__(self, config: SubnotoConfig, http_client: Optional[httpx.AsyncClient] = None):
39
+ self.config = config
40
+ self.session_id: Optional[str] = None
41
+ self.handshake_in_progress = False
42
+ self.cookie_jar = CookieJar()
43
+ self.http_client = http_client # Use provided client for handshake (with signatures)
44
+
45
+ # Create Oak client session using PyO3
46
+ self._session = PyClientSession(
47
+ unattested=config.unattested,
48
+ attester_key=config.attester_key
49
+ )
50
+
51
+ def _is_session_open(self) -> bool:
52
+ """Check if the session is open"""
53
+ return self._session.is_open()
54
+
55
+ async def ensure_session(self) -> None:
56
+ """Ensure session is established, performing handshake if needed"""
57
+ if self._is_session_open():
58
+ return
59
+
60
+ if self.handshake_in_progress:
61
+ # Wait for existing handshake
62
+ while self.handshake_in_progress:
63
+ await asyncio.sleep(0.05)
64
+ return
65
+
66
+ await self._handshake()
67
+
68
+ async def _handshake(self) -> None:
69
+ """Perform the Oak session handshake"""
70
+ self.handshake_in_progress = True
71
+
72
+ try:
73
+ max_steps = 4
74
+ step = 0
75
+
76
+ while not self._is_session_open() and step < max_steps:
77
+ step += 1
78
+
79
+ # Get outgoing handshake message
80
+ outgoing = self._session.get_outgoing_message()
81
+ if not outgoing:
82
+ break
83
+
84
+ if self._is_session_open():
85
+ break
86
+
87
+ # Send to server
88
+ url = f"{self.config.api_base_url}/tunnel/session"
89
+ headers = {"Content-Type": "application/octet-stream"}
90
+
91
+ if self.session_id:
92
+ headers["X-Session-Id"] = self.session_id
93
+
94
+ # Add cookies
95
+ cookies_str = self._get_cookies_for_request(url)
96
+ if cookies_str:
97
+ headers["Cookie"] = cookies_str
98
+
99
+ # Use provided client if available (has signatures), otherwise create new one
100
+ if self.http_client:
101
+ response = await self.http_client.post(
102
+ url,
103
+ content=outgoing,
104
+ headers=headers
105
+ )
106
+ else:
107
+ async with httpx.AsyncClient() as client:
108
+ response = await client.post(
109
+ url,
110
+ content=outgoing,
111
+ headers=headers
112
+ )
113
+
114
+ # Extract session ID from first response
115
+ if not self.session_id:
116
+ session_id_header = response.headers.get("X-Session-Id")
117
+ if not session_id_header:
118
+ raise SubnotoError("No session ID received from server")
119
+ self.session_id = session_id_header
120
+
121
+ if not response.is_success:
122
+ error_text = response.text
123
+ raise SubnotoError(
124
+ f"Handshake failed with status {response.status_code}: {error_text}",
125
+ response.status_code
126
+ )
127
+
128
+ # Store cookies
129
+ self._store_cookies(response, url)
130
+
131
+ # Process response
132
+ response_data = response.content
133
+ if len(response_data) > 0:
134
+ self._session.put_incoming_message(bytes(response_data))
135
+ else:
136
+ raise SubnotoError("Empty response from server during handshake")
137
+
138
+ if not self._is_session_open() or not self.session_id:
139
+ raise SubnotoError("Failed to establish session after handshake")
140
+
141
+ finally:
142
+ self.handshake_in_progress = False
143
+
144
+ def encrypt_request(self, plaintext: bytes) -> bytes:
145
+ """Encrypt a request body"""
146
+ if not self._is_session_open():
147
+ raise SubnotoError("Session not open")
148
+
149
+ try:
150
+ # PyClientSession.write expects string, returns bytes
151
+ plaintext_str = plaintext.decode('utf-8')
152
+ self._session.write(plaintext_str)
153
+
154
+ # Get the encrypted message
155
+ encrypted = self._session.get_outgoing_message()
156
+ if not encrypted:
157
+ raise SubnotoError("No encrypted message available")
158
+
159
+ return encrypted
160
+ except Exception as e:
161
+ raise SubnotoError(f"Encryption failed: {e}")
162
+
163
+ def decrypt_response(self, encrypted: bytes) -> bytes:
164
+ """Decrypt a response body"""
165
+ if not self._is_session_open():
166
+ raise SubnotoError("Session not open")
167
+
168
+ try:
169
+ # Put the encrypted response into the session
170
+ self._session.put_incoming_message(encrypted)
171
+
172
+ # Read the decrypted plaintext
173
+ decrypted_str = self._session.read()
174
+ if decrypted_str is None:
175
+ raise SubnotoError("No decrypted message available")
176
+
177
+ return decrypted_str.encode('utf-8')
178
+ except Exception as e:
179
+ raise SubnotoError(f"Decryption failed: {e}")
180
+
181
+ def get_session_id(self) -> Optional[str]:
182
+ """Get the current session ID"""
183
+ return self.session_id
184
+
185
+ def _get_cookies_for_request(self, url: str) -> str:
186
+ """Get cookies for a request URL"""
187
+ from urllib.request import Request as UrllibRequest
188
+ request = UrllibRequest(url)
189
+ self.cookie_jar.add_cookie_header(request)
190
+ return request.get_header("Cookie", "")
191
+
192
+ def _store_cookies(self, response: httpx.Response, url: str) -> None:
193
+ """Store cookies from a response"""
194
+ # Extract Set-Cookie headers and add to jar
195
+ for cookie_str in response.headers.get_list("set-cookie"):
196
+ # Parse cookie string into Cookie object
197
+ try:
198
+ # Simple parsing - in production might want to use http.cookies
199
+ parts = cookie_str.split(';')[0].split('=', 1)
200
+ if len(parts) == 2:
201
+ name, value = parts
202
+ parsed_url = urlparse(url)
203
+ cookie = Cookie(
204
+ version=0,
205
+ name=name.strip(),
206
+ value=value.strip(),
207
+ port=None,
208
+ port_specified=False,
209
+ domain=parsed_url.netloc,
210
+ domain_specified=True,
211
+ domain_initial_dot=False,
212
+ path='/',
213
+ path_specified=True,
214
+ secure=False,
215
+ expires=None,
216
+ discard=True,
217
+ comment=None,
218
+ comment_url=None,
219
+ rest={},
220
+ rfc2109=False
221
+ )
222
+ self.cookie_jar.set_cookie(cookie)
223
+ except Exception:
224
+ pass # Skip malformed cookies
225
+
226
+ def destroy(self) -> None:
227
+ """Destroy the session"""
228
+ self._session = None
229
+ self.session_id = None
230
+
231
+ def get_attestation_results(self) -> Optional[str]:
232
+ """Get attestation results as JSON string"""
233
+ # PyClientSession doesn't expose this yet
234
+ return None
235
+
236
+ def get_attestation_status(self) -> Optional[str]:
237
+ """Get attestation status as JSON string"""
238
+ # PyClientSession doesn't expose this yet
239
+ return None