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
This commit is contained in:
Harald Welte 2022-07-23 13:44:20 +02:00
parent fc31548c11
commit 3f3b45a27b
1 changed files with 64 additions and 54 deletions

View File

@ -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"
class SimRestServer:
app = Klein()
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:
@app.handle_errors(NoCardError)
def no_card_error(self, request, failure):
set_headers(request)
request.setResponseCode(410)
return "No SIM card inserted in slot"
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 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 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)