-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
176 lines (144 loc) · 5.75 KB
/
app.py
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
import base64
import urllib
from flask import Flask, flash, get_flashed_messages, redirect, url_for, render_template, request
app = Flask(__name__)
app.secret_key = b'not a secret'
@app.route('/', methods=['GET', 'POST'])
def index():
# Our four textarea contents
client_plain = ""
client_encoded = ""
server_plain = ""
server_encoded = ""
encode_error = ""
decode_error = ""
operation = request.form.get("operation")
no_padding = True
if request.form.get("submitCheck", None) == "submitted":
no_padding = request.form.get("no-padding", None) is not None
iiif_content = request.args.get("iiif-content")
if iiif_content is not None:
# flash this content to take it off the query string
flash(iiif_content)
return redirect(url_for('index'))
messages = get_flashed_messages()
if messages:
iiif_content = messages[0]
radios = {
"simple": None,
"unicode": None,
"encodeuri": None
}
encoding = request.form.get("encoding")
if not encoding:
encoding = "encodeuri" # Content State 0.9
radios[encoding] = "checked"
if iiif_content is not None:
server_encoded = iiif_content
try:
server_plain = decode(iiif_content, encoding, no_padding)
except Exception as ex:
decode_error = repr(ex)
if operation == "serverEncode":
server_plain = request.form.get("server-plain")
try:
server_encoded = encode(server_plain, encoding, no_padding)
except Exception as ex:
encode_error = repr(ex)
elif operation == "serverDecode":
server_encoded = request.form.get("server-encoded")
try:
server_plain = decode(server_encoded, encoding, no_padding)
except Exception as ex:
decode_error = repr(ex)
elif operation == "clientServerEncode":
client_plain = request.form.get("client-plain")
server_plain = client_plain
try:
server_encoded = encode(server_plain, encoding, no_padding)
except Exception as ex:
encode_error = repr(ex)
elif operation == "serverClientDecode":
server_encoded = request.form.get("server-encoded")
client_encoded = server_encoded
try:
server_plain = decode(server_encoded, encoding, no_padding)
except Exception as ex:
decode_error = repr(ex)
chk_no_padding = "checked" if no_padding else ""
return render_template("index.html", operation=operation,
radios=radios, chk_no_padding=chk_no_padding,
client_plain=client_plain, client_encoded=client_encoded,
server_plain=server_plain, server_encoded=server_encoded,
encode_error=encode_error, decode_error=decode_error)
def encode(plain_text, method, no_padding):
if method == "simple":
return encode_normal_utf8(plain_text, no_padding)
elif method == "unicode":
# going to do exactly the same here to demonstrate the problem
return encode_normal_utf8(plain_text, no_padding)
elif method == "encodeuri":
return encode_uricomponent(plain_text, no_padding)
else:
raise Exception("Unknown encoding option " + method)
def decode(content_state, method, no_padding):
if method == "simple":
return decode_normal_utf8(content_state, no_padding)
elif method == "unicode":
# going to do exactly the same here to demonstrate the problem
return decode_normal_utf8(content_state, no_padding)
elif method == "encodeuri":
return decode_uricomponent(content_state, no_padding)
else:
raise Exception("Unknown encoding option " + method)
def encode_normal_utf8(plain_text, no_padding):
binary = plain_text.encode("UTF-8")
base64url = base64.urlsafe_b64encode(binary) # this is bytes
utf8_decoded = base64url.decode("UTF-8")
if no_padding:
utf8_decoded = remove_padding(utf8_decoded)
return utf8_decoded
def decode_normal_utf8(content_state, no_padding):
if no_padding:
content_state = restore_padding(content_state)
binary = base64.urlsafe_b64decode(content_state)
plain_text = binary.decode("UTF-8")
return plain_text
def encode_uricomponent(plain_text, no_padding):
print(f"Encoding URIComponent {plain_text}")
quoted = urllib.parse.quote(plain_text, safe='') # safe=',/?:@&=+$#')
print(f"quoted: {quoted}")
binary = quoted.encode("UTF-8")
print(f"binary: {binary}")
base64url = base64.urlsafe_b64encode(binary) # this is bytes
print(f"base64url: {base64url}")
utf8_decoded = base64url.decode("UTF-8")
print(f"utf8_decoded: {utf8_decoded}")
if no_padding:
utf8_decoded = remove_padding(utf8_decoded)
print(f"unpadded: {utf8_decoded}")
return utf8_decoded
def decode_uricomponent(content_state, no_padding):
if no_padding:
content_state = restore_padding(content_state)
binary = base64.urlsafe_b64decode(content_state)
plain_text = binary.decode("UTF-8")
unquoted = urllib.parse.unquote(plain_text)
return unquoted
# Padding
# base64url spec says:
# The pad character "=" is typically percent-encoded when used in an URI, but if the data length is known
# implicitly, this can be avoided by skipping the padding.
def remove_padding(s):
return s.replace("=", "")
def restore_padding(s):
# The length of the restored string must be a multiple of 4
pad = len(s) % 4
padding = ""
if pad:
if pad == 1:
raise Exception("InvalidLengthError: Input base64url string is the wrong length to determine padding")
padding = "=" * (4 - pad)
return s + padding
if __name__ == '__main__':
app.run()