summaryrefslogtreecommitdiffstats
path: root/pkb_client/cli/cli.py
blob: 4bf53cdc3aeaf99c590e36890db704e64fd9e0a0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
import argparse
import dataclasses
import json
import os
import textwrap
from datetime import datetime

from pkb_client.client import PKBClient, API_ENDPOINT
from pkb_client.client.dns import DNSRecordType, DNSRestoreMode
from pkb_client.client.forwarding import URLForwardingType


class CustomJSONEncoder(json.JSONEncoder):
    def default(self, o):
        if isinstance(o, datetime):
            return o.isoformat()
        if dataclasses.is_dataclass(o):
            return dataclasses.asdict(o)
        return super().default(o)


def main():
    parser = argparse.ArgumentParser(
        description="Python client for the Porkbun API",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog=textwrap.dedent("""
                                    License:
                                    MIT - Copyright (c) Marvin Heptner
                                    """),
    )

    parser.add_argument(
        "-k",
        "--key",
        help='The API key used for Porkbun API calls (usually starts with "pk").',
    )
    parser.add_argument(
        "-s",
        "--secret",
        help='The API secret used for Porkbun API calls (usually starts with "sk").',
    )
    parser.add_argument("--debug", help="Enable debug mode.", action="store_true")
    parser.add_argument(
        "--endpoint", help="The API endpoint to use.", default=API_ENDPOINT
    )

    subparsers = parser.add_subparsers(help="Supported API methods")

    parser_ping = subparsers.add_parser("ping", help="Ping the API Endpoint")
    parser_ping.set_defaults(func=PKBClient.ping)

    parser_dns_create = subparsers.add_parser(
        "create-dns-record", help="Create a new DNS record."
    )
    parser_dns_create.set_defaults(func=PKBClient.create_dns_record)
    parser_dns_create.add_argument(
        "domain", help="The domain for which the new DNS record should be created."
    )
    parser_dns_create.add_argument(
        "record_type",
        help="The type of the new DNS record.",
        choices=list(DNSRecordType),
    )
    parser_dns_create.add_argument("content", help="The content of the new DNS record.")
    parser_dns_create.add_argument(
        "--name",
        help="The subdomain for which the new DNS record should be created."
        "The * can be used for a wildcard DNS record."
        "If not used, then a DNS record for the root domain will be created",
        required=False,
    )
    parser_dns_create.add_argument(
        "--ttl", type=int, help="The ttl of the new DNS record.", required=False
    )
    parser_dns_create.add_argument(
        "--prio", type=int, help="The priority of the new DNS record.", required=False
    )

    parser_dns_edit = subparsers.add_parser(
        "update-dns-record", help="Edit an existing DNS record."
    )
    parser_dns_edit.set_defaults(func=PKBClient.update_dns_record)
    parser_dns_edit.add_argument(
        "domain", help="The domain for which the DNS record should be edited."
    )
    parser_dns_edit.add_argument(
        "record_id", help="The id of the DNS record which should be edited."
    )
    parser_dns_edit.add_argument(
        "record_type",
        help="The new type of the DNS record.",
        choices=list(DNSRecordType),
    )
    parser_dns_edit.add_argument("content", help="The new content of the DNS record.")
    parser_dns_edit.add_argument(
        "--name",
        help="The new value of the subdomain for which the DNS record should apply. "
        "The * can be used for a wildcard DNS record. If not set, the record will "
        "be set for the root domain.",
        required=False,
    )
    parser_dns_edit.add_argument(
        "--ttl", type=int, help="The new ttl of the DNS record.", required=False
    )
    parser_dns_edit.add_argument(
        "--prio", type=int, help="The new priority of the DNS record.", required=False
    )

    parser_dns_delete = subparsers.add_parser(
        "delete-dns-records", help="Delete an existing DNS record."
    )
    parser_dns_delete.set_defaults(func=PKBClient.delete_dns_record)
    parser_dns_delete.add_argument(
        "domain", help="The domain for which the DNS record should be deleted."
    )
    parser_dns_delete.add_argument(
        "record_id", help="The id of the DNS record which should be deleted."
    )

    parser_dns_receive = subparsers.add_parser(
        "get-dns-records", help="Get all DNS records."
    )
    parser_dns_receive.set_defaults(func=PKBClient.get_dns_records)
    parser_dns_receive.add_argument(
        "domain", help="The domain for which the DNS record should be retrieved."
    )

    parser_dns_export = subparsers.add_parser(
        "export-dns-records", help="Save all DNS records to a local json file."
    )
    parser_dns_export.set_defaults(func=PKBClient.export_dns_records)
    parser_dns_export.add_argument(
        "domain",
        help="The domain for which the DNS record should be retrieved and saved.",
    )
    parser_dns_export.add_argument(
        "filepath", help="The filepath where to save the exported DNS records."
    )

    parser_dns_export_bind = subparsers.add_parser(
        "export-bind-dns-records", help="Save all DNS records to a local BIND file."
    )
    parser_dns_export_bind.set_defaults(func=PKBClient.export_bind_dns_records)
    parser_dns_export_bind.add_argument(
        "domain",
        help="The domain for which the DNS record should be retrieved and saved.",
    )
    parser_dns_export_bind.add_argument(
        "filepath", help="The filepath where to save the exported DNS records."
    )

    parser_dns_import = subparsers.add_parser(
        "import-dns-records",
        help="Restore all DNS records from a local json file.",
        formatter_class=argparse.RawTextHelpFormatter,
    )
    parser_dns_import.set_defaults(func=PKBClient.import_dns_records)
    parser_dns_import.add_argument(
        "domain", help="The domain for which the DNS record should be restored."
    )
    parser_dns_import.add_argument(
        "filepath", help="The filepath from which the DNS records are to be restored."
    )
    parser_dns_import.add_argument(
        "restore_mode",
        help="""The restore mode (DNS records are identified by the record type, name and prio if supported):
    clear: remove all existing DNS records and restore all DNS records from the provided file
    replace: replace only existing DNS records with the DNS records from the provided file, but do not create any new DNS records
    keep: keep the existing DNS records and only create new ones for all DNS records from the specified file if they do not exist
    """,
        type=DNSRestoreMode.from_string,
        choices=list(DNSRestoreMode),
    )

    parser_dns_import_bind = subparsers.add_parser(
        "import-bind-dns-records",
        help="Restore all DNS records from a local BIND file.",
        formatter_class=argparse.RawTextHelpFormatter,
    )
    parser_dns_import_bind.set_defaults(func=PKBClient.import_bind_dns_records)
    parser_dns_import_bind.add_argument(
        "filepath", help="The filepath from which the DNS records are to be restored."
    )
    parser_dns_import_bind.add_argument(
        "restore_mode",
        help="""The restore mode (DNS records are identified by the record id):
    clear: remove all existing DNS records and restore all DNS records from the provided file
    """,
        type=DNSRestoreMode.from_string,
        choices=[DNSRestoreMode.clear],
    )

    parser_domain_pricing = subparsers.add_parser(
        "get-domain-pricing", help="Get the pricing for Porkbun domains."
    )
    parser_domain_pricing.set_defaults(func=PKBClient.get_domain_pricing)

    parser_ssl_retrieve = subparsers.add_parser(
        "get-ssl-bundle", help="Retrieve an SSL bundle for given domain."
    )
    parser_ssl_retrieve.set_defaults(func=PKBClient.get_ssl_bundle)
    parser_ssl_retrieve.add_argument(
        "domain", help="The domain for which the SSL bundle should be retrieve."
    )

    parser_update_dns_server = subparsers.add_parser(
        "update-dns-servers", help="Update the DNS servers for a domain."
    )
    parser_update_dns_server.set_defaults(func=PKBClient.update_dns_servers)
    parser_update_dns_server.add_argument(
        "domain", help="The domain for which the DNS servers should be set."
    )
    parser_update_dns_server.add_argument(
        "dns_servers", nargs="+", help="The DNS servers to be set."
    )

    parser_get_dns_server = subparsers.add_parser(
        "get-dns-servers", help="Retrieve the DNS servers for a domain."
    )
    parser_get_dns_server.set_defaults(func=PKBClient.get_dns_servers)
    parser_get_dns_server.add_argument(
        "domain", help="The domain for which the DNS servers should be retrieved."
    )

    parser_list_domains = subparsers.add_parser(
        "get-domains", help="List all domains in this account in chunks of 1000."
    )
    parser_list_domains.set_defaults(func=PKBClient.get_domains)
    parser_list_domains.add_argument(
        "--start",
        type=int,
        help="The start index of the list.",
        default=0,
        required=False,
    )

    parser_get_url_forward = subparsers.add_parser(
        "get-url-forwards", help="Retrieve all URL forwards."
    )
    parser_get_url_forward.set_defaults(func=PKBClient.get_url_forwards)
    parser_get_url_forward.add_argument(
        "domain", help="The domain for which the URL forwards should be retrieved."
    )

    parser_add_url_forward = subparsers.add_parser(
        "create-url-forward", help="Create a new URL forward."
    )
    parser_add_url_forward.set_defaults(func=PKBClient.create_url_forward)
    parser_add_url_forward.add_argument(
        "domain", help="The domain for which the new URL forward should be created."
    )
    parser_add_url_forward.add_argument(
        "location",
        help="The location to which the url forwarding should redirect.",
    )
    parser_add_url_forward.add_argument(
        "type", help="The type of the url forwarding.", choices=list(URLForwardingType)
    )
    parser_add_url_forward.add_argument(
        "--subdomain",
        help="The subdomain for which the url forwarding should be added.",
        required=False,
        default="",
    )
    parser_add_url_forward.add_argument(
        "--include-path",
        help="Whether the path should be included in the url forwarding.",
        action="store_true",
        default=False,
    )
    parser_add_url_forward.add_argument(
        "--wildcard",
        help="Whether the url forwarding should be also applied to subdomains.",
        action="store_true",
        default=False,
    )

    parser_delete_url_forward = subparsers.add_parser(
        "delete-url-forward", help="Delete an existing URL forward."
    )
    parser_delete_url_forward.set_defaults(func=PKBClient.delete_url_forward)
    parser_delete_url_forward.add_argument(
        "domain", help="The domain for which the URL forward should be deleted."
    )
    parser_delete_url_forward.add_argument(
        "id", help="The id of the URL forward which should be deleted."
    )

    args = vars(parser.parse_args())

    debug = args.pop("debug", False)

    func = args.pop("func", None)
    if not func:
        raise argparse.ArgumentError(
            None, "No method specified. Please provide a method and try again."
        )

    endpoint = args.pop("endpoint")
    api_key = args.pop("key")
    api_secret = args.pop("secret")

    # call the api methods which do not require authentication
    if func == PKBClient.get_domain_pricing:
        pkb_client = PKBClient(api_endpoint=endpoint, debug=debug)
        ret = func(pkb_client, **args)

        print(json.dumps(ret, cls=CustomJSONEncoder, indent=4))
        exit(0)

    if api_key is None:
        # try to get the api key from the environment variable or fallback to user input
        api_key = os.environ.get("PKB_API_KEY", "")
        if len(api_key.strip()) == 0:
            while True:
                api_key = input(
                    'Please enter your API key you got from Porkbun (usually starts with "pk"): '
                )
                if len(api_key.strip()) == 0:
                    print("The api key can not be empty.")
                else:
                    break

    if api_secret is None:
        # try to get the api secret from the environment variable or fallback to user input
        api_secret = os.environ.get("PKB_API_SECRET", "")
        if len(api_secret.strip()) == 0:
            while True:
                api_secret = input(
                    'Please enter your API key secret you got from Porkbun (usually starts with "sk"): '
                )
                if len(api_secret.strip()) == 0:
                    print("The api key secret can not be empty.")
                else:
                    break

    pkb_client = PKBClient(
        api_key=api_key, secret_api_key=api_secret, api_endpoint=endpoint, debug=debug
    )

    ret = func(pkb_client, **args)

    print(json.dumps(ret, cls=CustomJSONEncoder, indent=4))


if __name__ == "__main__":
    main()