neels has uploaded this change for review. (
https://gerrit.osmocom.org/c/pysim/+/40201?usp=email )
Change subject: personalization: make AlgorithmID a new EnumParam
......................................................................
personalization: make AlgorithmID a new EnumParam
The AlgorithmID has a few preset values, and hardly anyone knows which
is which. So instead of entering '1', '2' or '3', make it work
with
prededined values 'Milenage', 'TUAK' and 'usim-test'.
Implement the enum value part abstractly in new EnumParam.
Make AlgorithmID a subclass of EnumParam and define the values as from
pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn
Related: SYS#6768
Change-Id: I71c2ec1b753c66cb577436944634f32792353240
---
M pySim/esim/saip/personalization.py
1 file changed, 92 insertions(+), 12 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/01/40201/1
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index 317cac5..1ce420a 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -18,6 +18,7 @@
import abc
import io
import copy
+import re
from typing import List, Tuple, Generator, Optional
from osmocom.tlv import camel_to_snake
@@ -338,6 +339,70 @@
return bytes(val)
+class EnumParam(ConfigurableParameter):
+ value_map = {
+ # For example:
+ #'Meaningful label for value 23': 0x23,
+ # Where 0x23 is a valid value to use for apply_val().
+ }
+ _value_map_reverse = None
+
+ @classmethod
+ def validate_val(cls, val):
+ orig_val = val
+ enum_val = None
+ if isinstance(val, str):
+ enum_name = val
+ enum_val = cls.map_name_to_val(enum_name)
+
+ # if the str is not one of the known value_map.keys(), is it maybe one of
value_map.keys()?
+ if enum_val is None and val in cls.value_map.values():
+ enum_val = val
+
+ if enum_val not in cls.value_map.values():
+ raise ValueError(f"{cls.get_name()}: invalid argument: {orig_val!r}.
Valid arguments are:"
+ f" {', '.join(cls.value_map.keys())}")
+
+ return enum_val
+
+ @classmethod
+ def map_name_to_val(cls, name:str, strict=True):
+ val = cls.value_map.get(name)
+ if val is not None:
+ return val
+
+ clean_name = cls.clean_name_str(name)
+ for k, v in cls.value_map.items():
+ if clean_name == cls.clean_name_str(k):
+ return v
+
+ if strict:
+ raise ValueError(f"Problem in {cls.get_name()}: {name!r} is not a known
value."
+ f" Known values are: {cls.value_map.keys()!r}")
+ return None
+
+ @classmethod
+ def map_val_to_name(cls, val, strict=False) -> str:
+ if cls._value_map_reverse is None:
+ cls._value_map_reverse = dict((v, k) for k, v in cls.value_map.items())
+
+ name = cls._value_map_reverse.get(val)
+ if name:
+ return name
+ if strict:
+ raise ValueError(f"Problem in {cls.get_name()}: {val!r} ({type(val)}) is
not a known value."
+ f" Known values are: {cls.value_map.values()!r}")
+ return None
+
+ @classmethod
+ def name_normalize(cls, name:str) -> str:
+ return cls.map_val_to_name(cls.map_name_to_val(name))
+
+ @classmethod
+ def clean_name_str(cls, val):
+ return re.sub('[^0-9A-Za-z-_]', '', val).lower()
+
+
class Iccid(DecimalParam):
"""ICCID Parameter. Input: string of decimal digits.
If the string of digits is only 18 digits long, add a Luhn check
digit."""
@@ -714,22 +779,37 @@
# if it is an int (algorithmID), just pass thru as int
yield { cls.name: val }
-
-class AlgorithmID(DecimalParam, AlgoConfig):
+class AlgorithmID(EnumParam, AlgoConfig):
+ '''use validate_val() from EnumParam, and apply_val() from AlgoConfig.
+ In get_values_from_pes(), return enum value names, not raw values.'''
is_abstract = False
- algo_config_key = 'algorithmID'
- allow_len = 1
- default_value = 1 # Milenage
+ name = "Algorithm"
+
+ # as in pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn
+ value_map = {
+ "Milenage" : 1,
+ "TUAK" : 2,
+ "usim-test" : 3,
+ }
+ default_value = "Milenage"
default_source = param_source.ConstantSource
+ algo_config_key = 'algorithmID'
+
+ # EnumParam.validate_val() returns the int values from value_map
+
@classmethod
- def validate_val(cls, val):
- val = super().validate_val(val)
- val = int(val)
- valid = (1, 2, 3)
- if val not in valid:
- raise ValueError(f'Invalid algorithmID {val!r}, must be one of
{valid}')
- return val
+ def get_values_from_pes(cls, pes: ProfileElementSequence):
+ # return enum names, not raw values.
+ # use of super(): this intends to call AlgoConfig.get_values_from_pes() so that
the cls argument is this cls
+ # here (AlgorithmID); i.e. AlgoConfig.get_values_from_pes(pes) doesn't work,
because AlgoConfig needs to look up
+ # cls.algo_config_key.
+ for d in super(cls, cls).get_values_from_pes(pes):
+ if cls.name in d:
+ # convert int to value string
+ val = d[cls.name]
+ d[cls.name] = cls.map_val_to_name(val, strict=True)
+ yield d
class K(BinaryParam, AlgoConfig):
--
To view, visit
https://gerrit.osmocom.org/c/pysim/+/40201?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: newchange
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I71c2ec1b753c66cb577436944634f32792353240
Gerrit-Change-Number: 40201
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>