This repository was archived by the owner on Dec 28, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnfsnapi.py
More file actions
134 lines (112 loc) · 5.38 KB
/
nfsnapi.py
File metadata and controls
134 lines (112 loc) · 5.38 KB
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
"""Stuff to make working with the NearlyFreeSpeech.NET API easier.
>>> import nfsnapi
>>> # Replace USERNAME, API_KEY, and so on with actual values.
>>> nfsnapi.run_request("USERNAME", "API_KEY",
... "/account/ACCOUNT_NUMBER/balance")
'10.56'
>>> nfsnapi.run_request("USERNAME", "API_KEY",
... "/dns/DOMAIN/listRRs", "type=A")
(A bunch of JSON not shown.)
>>> # And so on...
This file was written by Damien Dart, <damiendart@pobox.com>. This is
free and unencumbered software released into the public domain. For more
information, please refer to the accompanying "UNLICENCE" file.
"""
__author__ = "Damien Dart, <damiendart@pobox.com>"
__license__ = "Unlicense"
__title__ = "nfsnapi"
__version__ = "0.3.0"
import json
import random
import string
import time
from hashlib import sha1
try:
from http.client import HTTPException
from urllib.request import urlopen, Request
from urllib.error import HTTPError, URLError
basestring = str
except ImportError:
from httplib import HTTPException
from urllib2 import urlopen, Request, HTTPError, URLError
def auth_header(username, API_key, request_path, request_body = b""):
"""Return a NearlyFreeSpeeech.NET authentication HTTP header field.
Returns a dictionary containing an authentication HTTP header field
required for NearlyFreeSpeech.NET API requests. For more information,
see <https://members.nearlyfreespeech.net/wiki/API/Introduction>.
- "username" should be a string containing the member login name of
the user making the request.
- "API_key" should be a string containing the API key associated with
the member login name; an API key can be obtained by submitting a
secure support request to NearlyFreeSpeeech.NET.
- "request_path" should be a string containing the path portion of the
requested URL. For example, if the requested URL is
<https://api.nearlyfreespeech.net/site/example/addAlias>,
"request_path" would be "/site/example/addAlias". The first
forward-slash is optional.
- "request_body" may be a bytestring containing the HTTP request
message body for HTTP POST requests, or an empty bytestring for GET
requests or if no such data is required. The data should be in the
standard "application/x-www-form-urlencoded" format.
"""
if (request_path[0] != "/"):
request_path = "/%s" % request_path
salt = "".join(random.choice(string.ascii_letters) for i in range(16))
timestamp = str(int(time.time()))
return { "X-NFSN-Authentication" : ";".join([username, timestamp, salt,
sha1(str(";".join([username, timestamp, salt, API_key, request_path,
sha1(request_body).hexdigest()])).encode("utf-8")).hexdigest()]) }
def run_request(username, API_key, request_path, request_body = None):
"""Run a NearlyFreeSpeech.NET API request, return a string response.
NOTE: This function does not verify the API server's certificate.
The NearlyFreeSpeech.net API documentation is unclear on whether every
successful API call returns a valid JSON-encoded associative array,
hence why any response is returned as a string. This method raises
"NFSNAPIRequestError" on errors.
- "username" should be a string containing the member login name of
the user making the request.
- "API_key" should be a string containing the API key associated with
the member login name; an API key can be obtained by submitting a
secure support request to NearlyFreeSpeeech.NET.
- "request_path" should be a string containing the path portion of the
requested URL. For example, if the requested URL is
<https://api.nearlyfreespeech.net/site/example/addAlias>,
"request_path" would be "/site/example/addAlias". The first
forward-slash is optional.
- "request_body" may be a string containing the HTTP request message
body for HTTP POST requests or "None" for HTTP GET requests. Pass
an empty string for HTTP POST requests that do not require a message
body. The data should be in the standard
"application/x-www-form-urlencoded" format.
"""
try:
if (request_path[0] != "/"):
request_path = "/%s" % request_path
if isinstance(request_body, basestring):
request_body = request_body.encode("utf-8")
return urlopen(Request("https://api.nearlyfreespeech.net" + request_path,
request_body, dict(auth_header(username, API_key, request_path,
request_body or b""), **{"User-Agent": "nfsnapi/" + __version__ +
" +https://www.robotinaponcho.net/git/?p=nfsnapi-python.git"}))).read().decode()
except HTTPException as e:
raise NFSNAPIRequestError(str(e))
except HTTPError as e:
try:
error = json.loads(e.read().decode())
raise NFSNAPIRequestError("\n".join([error["error"], error["debug"]]))
except (KeyError, ValueError):
raise NFSNAPIRequestError(str(e.reason))
except URLError as e:
raise NFSNAPIRequestError(str(e.reason))
class NFSNAPIRequestError(Exception):
"""Raised when an NearlyFreeSpeech.NET API request fails.
Every instance will have a "reason" attribute, a string with the
reason for the error. If the offending request resulted in a 4XX or
5XX HTTP response, the attribute will contain the "human-readable" and
debug error messages returned by the NearlyFreeSpeech.NET API,
separated by a new-line (for more information, see
<https://members.nearlyfreespeech.net/wiki/API/Introduction>).
"""
def __init__(self, reason):
Exception.__init__(self, reason)
self.reason = reason