Skip to content

Commit 3fec816

Browse files
Add PDF encryption methods
Assisted-by: Codex
1 parent cde8bb2 commit 3fec816

2 files changed

Lines changed: 295 additions & 0 deletions

File tree

src/pdfrest/client.py

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@
8282
JpegPdfRestPayload,
8383
OcrPdfPayload,
8484
PdfCompressPayload,
85+
PdfDecryptPayload,
86+
PdfEncryptPayload,
8587
PdfFlattenAnnotationsPayload,
8688
PdfFlattenFormsPayload,
8789
PdfFlattenTransparenciesPayload,
@@ -2761,6 +2763,107 @@ def change_permissions_password(
27612763
timeout=timeout,
27622764
)
27632765

2766+
def add_open_password(
2767+
self,
2768+
file: PdfRestFile | Sequence[PdfRestFile],
2769+
*,
2770+
new_open_password: str,
2771+
current_permissions_password: str | None = None,
2772+
output: str | None = None,
2773+
extra_query: Query | None = None,
2774+
extra_headers: AnyMapping | None = None,
2775+
extra_body: Body | None = None,
2776+
timeout: TimeoutTypes | None = None,
2777+
) -> PdfRestFileBasedResponse:
2778+
"""Encrypt a PDF with a new open password."""
2779+
2780+
payload: dict[str, Any] = {
2781+
"files": file,
2782+
"new_open_password": new_open_password,
2783+
}
2784+
if current_permissions_password is not None:
2785+
payload["current_permissions_password"] = current_permissions_password
2786+
if output is not None:
2787+
payload["output"] = output
2788+
2789+
return self._post_file_operation(
2790+
endpoint="/encrypted-pdf",
2791+
payload=payload,
2792+
payload_model=PdfEncryptPayload,
2793+
extra_query=extra_query,
2794+
extra_headers=extra_headers,
2795+
extra_body=extra_body,
2796+
timeout=timeout,
2797+
)
2798+
2799+
def change_open_password(
2800+
self,
2801+
file: PdfRestFile | Sequence[PdfRestFile],
2802+
*,
2803+
current_open_password: str,
2804+
new_open_password: str,
2805+
current_permissions_password: str | None = None,
2806+
output: str | None = None,
2807+
extra_query: Query | None = None,
2808+
extra_headers: AnyMapping | None = None,
2809+
extra_body: Body | None = None,
2810+
timeout: TimeoutTypes | None = None,
2811+
) -> PdfRestFileBasedResponse:
2812+
"""Rotate the open password for an encrypted PDF."""
2813+
2814+
payload: dict[str, Any] = {
2815+
"files": file,
2816+
"current_open_password": current_open_password,
2817+
"new_open_password": new_open_password,
2818+
}
2819+
if current_permissions_password is not None:
2820+
payload["current_permissions_password"] = current_permissions_password
2821+
if output is not None:
2822+
payload["output"] = output
2823+
2824+
return self._post_file_operation(
2825+
endpoint="/encrypted-pdf",
2826+
payload=payload,
2827+
payload_model=PdfEncryptPayload,
2828+
extra_query=extra_query,
2829+
extra_headers=extra_headers,
2830+
extra_body=extra_body,
2831+
timeout=timeout,
2832+
)
2833+
2834+
def remove_open_password(
2835+
self,
2836+
file: PdfRestFile | Sequence[PdfRestFile],
2837+
*,
2838+
current_open_password: str,
2839+
current_permissions_password: str | None = None,
2840+
output: str | None = None,
2841+
extra_query: Query | None = None,
2842+
extra_headers: AnyMapping | None = None,
2843+
extra_body: Body | None = None,
2844+
timeout: TimeoutTypes | None = None,
2845+
) -> PdfRestFileBasedResponse:
2846+
"""Decrypt a PDF by removing its open password."""
2847+
2848+
payload: dict[str, Any] = {
2849+
"files": file,
2850+
"current_open_password": current_open_password,
2851+
}
2852+
if current_permissions_password is not None:
2853+
payload["current_permissions_password"] = current_permissions_password
2854+
if output is not None:
2855+
payload["output"] = output
2856+
2857+
return self._post_file_operation(
2858+
endpoint="/decrypted-pdf",
2859+
payload=payload,
2860+
payload_model=PdfDecryptPayload,
2861+
extra_query=extra_query,
2862+
extra_headers=extra_headers,
2863+
extra_body=extra_body,
2864+
timeout=timeout,
2865+
)
2866+
27642867
def remove_permissions_password(
27652868
self,
27662869
file: PdfRestFile | Sequence[PdfRestFile],
@@ -3938,6 +4041,107 @@ async def remove_permissions_password(
39384041
timeout=timeout,
39394042
)
39404043

4044+
async def add_open_password(
4045+
self,
4046+
file: PdfRestFile | Sequence[PdfRestFile],
4047+
*,
4048+
new_open_password: str,
4049+
current_permissions_password: str | None = None,
4050+
output: str | None = None,
4051+
extra_query: Query | None = None,
4052+
extra_headers: AnyMapping | None = None,
4053+
extra_body: Body | None = None,
4054+
timeout: TimeoutTypes | None = None,
4055+
) -> PdfRestFileBasedResponse:
4056+
"""Asynchronously encrypt a PDF with a new open password."""
4057+
4058+
payload: dict[str, Any] = {
4059+
"files": file,
4060+
"new_open_password": new_open_password,
4061+
}
4062+
if current_permissions_password is not None:
4063+
payload["current_permissions_password"] = current_permissions_password
4064+
if output is not None:
4065+
payload["output"] = output
4066+
4067+
return await self._post_file_operation(
4068+
endpoint="/encrypted-pdf",
4069+
payload=payload,
4070+
payload_model=PdfEncryptPayload,
4071+
extra_query=extra_query,
4072+
extra_headers=extra_headers,
4073+
extra_body=extra_body,
4074+
timeout=timeout,
4075+
)
4076+
4077+
async def change_open_password(
4078+
self,
4079+
file: PdfRestFile | Sequence[PdfRestFile],
4080+
*,
4081+
current_open_password: str,
4082+
new_open_password: str,
4083+
current_permissions_password: str | None = None,
4084+
output: str | None = None,
4085+
extra_query: Query | None = None,
4086+
extra_headers: AnyMapping | None = None,
4087+
extra_body: Body | None = None,
4088+
timeout: TimeoutTypes | None = None,
4089+
) -> PdfRestFileBasedResponse:
4090+
"""Asynchronously rotate the open password for an encrypted PDF."""
4091+
4092+
payload: dict[str, Any] = {
4093+
"files": file,
4094+
"current_open_password": current_open_password,
4095+
"new_open_password": new_open_password,
4096+
}
4097+
if current_permissions_password is not None:
4098+
payload["current_permissions_password"] = current_permissions_password
4099+
if output is not None:
4100+
payload["output"] = output
4101+
4102+
return await self._post_file_operation(
4103+
endpoint="/encrypted-pdf",
4104+
payload=payload,
4105+
payload_model=PdfEncryptPayload,
4106+
extra_query=extra_query,
4107+
extra_headers=extra_headers,
4108+
extra_body=extra_body,
4109+
timeout=timeout,
4110+
)
4111+
4112+
async def remove_open_password(
4113+
self,
4114+
file: PdfRestFile | Sequence[PdfRestFile],
4115+
*,
4116+
current_open_password: str,
4117+
current_permissions_password: str | None = None,
4118+
output: str | None = None,
4119+
extra_query: Query | None = None,
4120+
extra_headers: AnyMapping | None = None,
4121+
extra_body: Body | None = None,
4122+
timeout: TimeoutTypes | None = None,
4123+
) -> PdfRestFileBasedResponse:
4124+
"""Asynchronously decrypt a PDF by removing its open password."""
4125+
4126+
payload: dict[str, Any] = {
4127+
"files": file,
4128+
"current_open_password": current_open_password,
4129+
}
4130+
if current_permissions_password is not None:
4131+
payload["current_permissions_password"] = current_permissions_password
4132+
if output is not None:
4133+
payload["output"] = output
4134+
4135+
return await self._post_file_operation(
4136+
endpoint="/decrypted-pdf",
4137+
payload=payload,
4138+
payload_model=PdfDecryptPayload,
4139+
extra_query=extra_query,
4140+
extra_headers=extra_headers,
4141+
extra_body=extra_body,
4142+
timeout=timeout,
4143+
)
4144+
39414145
async def compress_pdf(
39424146
self,
39434147
file: PdfRestFile | Sequence[PdfRestFile],

src/pdfrest/models/_internal.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,6 +1239,97 @@ class PdfUnrestrictPayload(BaseModel):
12391239
] = None
12401240

12411241

1242+
class PdfEncryptPayload(BaseModel):
1243+
"""Adapt caller options into a pdfRest-ready encrypt-PDF request payload."""
1244+
1245+
files: Annotated[
1246+
list[PdfRestFile],
1247+
Field(
1248+
min_length=1,
1249+
max_length=1,
1250+
validation_alias=AliasChoices("file", "files"),
1251+
serialization_alias="id",
1252+
),
1253+
BeforeValidator(_ensure_list),
1254+
AfterValidator(
1255+
_allowed_mime_types("application/pdf", error_msg="Must be a PDF file")
1256+
),
1257+
PlainSerializer(_serialize_as_first_file_id),
1258+
]
1259+
new_open_password: Annotated[
1260+
str,
1261+
Field(
1262+
serialization_alias="new_open_password",
1263+
min_length=6,
1264+
max_length=128,
1265+
),
1266+
]
1267+
current_open_password: Annotated[
1268+
str | None,
1269+
Field(
1270+
serialization_alias="current_open_password",
1271+
min_length=1,
1272+
max_length=128,
1273+
default=None,
1274+
),
1275+
] = None
1276+
current_permissions_password: Annotated[
1277+
str | None,
1278+
Field(
1279+
serialization_alias="current_permissions_password",
1280+
min_length=1,
1281+
max_length=128,
1282+
default=None,
1283+
),
1284+
] = None
1285+
output: Annotated[
1286+
str | None,
1287+
Field(serialization_alias="output", min_length=1, default=None),
1288+
AfterValidator(_validate_output_prefix),
1289+
] = None
1290+
1291+
1292+
class PdfDecryptPayload(BaseModel):
1293+
"""Adapt caller options into a pdfRest-ready decrypt-PDF request payload."""
1294+
1295+
files: Annotated[
1296+
list[PdfRestFile],
1297+
Field(
1298+
min_length=1,
1299+
max_length=1,
1300+
validation_alias=AliasChoices("file", "files"),
1301+
serialization_alias="id",
1302+
),
1303+
BeforeValidator(_ensure_list),
1304+
AfterValidator(
1305+
_allowed_mime_types("application/pdf", error_msg="Must be a PDF file")
1306+
),
1307+
PlainSerializer(_serialize_as_first_file_id),
1308+
]
1309+
current_open_password: Annotated[
1310+
str,
1311+
Field(
1312+
serialization_alias="current_open_password",
1313+
min_length=1,
1314+
max_length=128,
1315+
),
1316+
]
1317+
current_permissions_password: Annotated[
1318+
str | None,
1319+
Field(
1320+
serialization_alias="current_permissions_password",
1321+
min_length=1,
1322+
max_length=128,
1323+
default=None,
1324+
),
1325+
] = None
1326+
output: Annotated[
1327+
str | None,
1328+
Field(serialization_alias="output", min_length=1, default=None),
1329+
AfterValidator(_validate_output_prefix),
1330+
] = None
1331+
1332+
12421333
class BmpPdfRestPayload(BasePdfRestGraphicPayload[Literal["rgb", "gray"]]):
12431334
"""Adapt caller options into a pdfRest-ready BMP request payload."""
12441335

0 commit comments

Comments
 (0)