aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@osmocom.org>2022-07-23 13:44:20 +0200
committerHarald Welte <laforge@osmocom.org>2022-07-23 13:46:52 +0200
commit3f3b45a27b5b2f4b8913ab5308da33c41bc3531e (patch)
treeb649a4f84041854fbc75f0649c9bf10f559523de
parentfc31548c11afd58791b5979e5183e5f4a1d90bcd (diff)
sim-rest-server: Render error messages as JSON
Let's make sure even error messages are returned in JSON format. While at it, also reduce some code duplication between the 'auth' and 'info' route handlers by using the klein handle_errors decorator instead of manual exception catching. Change-Id: I1e0364e28ba7ce7451993f57c8228f9a7ade6b0e Closes: OS#5607
-rwxr-xr-xcontrib/sim-rest-server.py118
1 files changed, 64 insertions, 54 deletions
diff --git a/contrib/sim-rest-server.py b/contrib/sim-rest-server.py
index a31aeed..62498b4 100755
--- a/contrib/sim-rest-server.py
+++ b/contrib/sim-rest-server.py
@@ -21,7 +21,7 @@ import json
import sys
import argparse
-from klein import run, route
+from klein import Klein
from pySim.transport import ApduTracer
from pySim.transport.pcsc import PcscSimLink
@@ -50,78 +50,87 @@ def connect_to_card(slot_nr:int):
return tp, scc, card
+class ApiError:
+ def __init__(self, msg:str):
+ self.msg = msg
+
+ def __str__(self):
+ return json.dumps({'error': {'message':self.msg}})
+
+
def set_headers(request):
request.setHeader('Content-Type', 'application/json')
-@route('/sim-auth-api/v1/slot/<int:slot>')
-def auth(request, slot):
- """REST API endpoint for performing authentication against a USIM.
- Expects a JSON body containing RAND and AUTN.
- Returns a JSON body containing RES, CK, IK and Kc."""
- try:
- # there are two hex-string JSON parameters in the body: rand and autn
- content = json.loads(request.content.read())
- rand = content['rand']
- autn = content['autn']
- except:
- request.setResponseCode(400)
- return "Malformed Request"
-
- try:
- tp, scc, card = connect_to_card(slot)
- except ReaderError:
+class SimRestServer:
+ app = Klein()
+
+ @app.handle_errors(NoCardError)
+ def no_card_error(self, request, failure):
+ set_headers(request)
+ request.setResponseCode(410)
+ return str(ApiError("No SIM card inserted in slot"))
+
+ @app.handle_errors(ReaderError)
+ def reader_error(self, request, failure):
+ set_headers(request)
request.setResponseCode(404)
- return "Specified SIM Slot doesn't exist"
- except ProtocolError:
+ return str(ApiError("Reader Error: Specified SIM Slot doesn't exist"))
+
+ @app.handle_errors(ProtocolError)
+ def protocol_error(self, request, failure):
+ set_headers(request)
request.setResponseCode(500)
- return "Error"
- except NoCardError:
- request.setResponseCode(410)
- return "No SIM card inserted in slot"
+ return str(ApiError("Protocol Error"))
+
+ @app.handle_errors(SwMatchError)
+ def sw_match_error(self, request, failure):
+ set_headers(request)
+ request.setResponseCode(500)
+ return str(ApiError("Card Communication Error %s" % failure))
+
+
+ @app.route('/sim-auth-api/v1/slot/<int:slot>')
+ def auth(self, request, slot):
+ """REST API endpoint for performing authentication against a USIM.
+ Expects a JSON body containing RAND and AUTN.
+ Returns a JSON body containing RES, CK, IK and Kc."""
+ try:
+ # there are two hex-string JSON parameters in the body: rand and autn
+ content = json.loads(request.content.read())
+ rand = content['rand']
+ autn = content['autn']
+ except:
+ set_headers(request)
+ request.setResponseCode(400)
+ return str(ApiError("Malformed Request"))
+
+ tp, scc, card = connect_to_card(slot)
- try:
card.select_adf_by_aid(adf='usim')
res, sw = scc.authenticate(rand, autn)
- except SwMatchError as e:
- request.setResponseCode(500)
- return "Communication Error %s" % e
- tp.disconnect()
+ tp.disconnect()
- set_headers(request)
- return json.dumps(res, indent=4)
+ set_headers(request)
+ return json.dumps(res, indent=4)
-@route('/sim-info-api/v1/slot/<int:slot>')
-def info(request, slot):
- """REST API endpoint for obtaining information about an USIM.
- Expects empty body in request.
- Returns a JSON body containing ICCID, IMSI."""
+ @app.route('/sim-info-api/v1/slot/<int:slot>')
+ def info(self, request, slot):
+ """REST API endpoint for obtaining information about an USIM.
+ Expects empty body in request.
+ Returns a JSON body containing ICCID, IMSI."""
- try:
tp, scc, card = connect_to_card(slot)
- except ReaderError:
- request.setResponseCode(404)
- return "Specified SIM Slot doesn't exist"
- except ProtocolError:
- request.setResponseCode(500)
- return "Error"
- except NoCardError:
- request.setResponseCode(410)
- return "No SIM card inserted in slot"
- try:
card.select_adf_by_aid(adf='usim')
iccid, sw = card.read_iccid()
imsi, sw = card.read_imsi()
res = {"imsi": imsi, "iccid": iccid }
- except SwMatchError as e:
- request.setResponseCode(500)
- return "Communication Error %s" % e
- tp.disconnect()
+ tp.disconnect()
- set_headers(request)
- return json.dumps(res, indent=4)
+ set_headers(request)
+ return json.dumps(res, indent=4)
def main(argv):
@@ -132,7 +141,8 @@ def main(argv):
args = parser.parse_args()
- run(args.host, args.port)
+ srr = SimRestServer()
+ srr.app.run(args.host, args.port)
if __name__ == "__main__":
main(sys.argv)