mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-26 15:28:35 +03:00
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
This commit is contained in:
@@ -18,6 +18,7 @@
|
|||||||
import abc
|
import abc
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
from typing import List, Tuple, Generator, Optional
|
from typing import List, Tuple, Generator, Optional
|
||||||
|
|
||||||
from osmocom.tlv import camel_to_snake
|
from osmocom.tlv import camel_to_snake
|
||||||
@@ -352,6 +353,70 @@ class BinaryParam(ConfigurableParameter):
|
|||||||
return bytes(val)
|
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):
|
class Iccid(DecimalParam):
|
||||||
"""ICCID Parameter. Input: string of decimal digits.
|
"""ICCID Parameter. Input: string of decimal digits.
|
||||||
If the string of digits is only 18 digits long, add a Luhn check digit."""
|
If the string of digits is only 18 digits long, add a Luhn check digit."""
|
||||||
@@ -757,21 +822,36 @@ class AlgoConfig(ConfigurableParameter):
|
|||||||
# if it is an int (algorithmID), just pass thru as int
|
# if it is an int (algorithmID), just pass thru as int
|
||||||
yield { cls.name: val }
|
yield { cls.name: val }
|
||||||
|
|
||||||
|
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.'''
|
||||||
|
name = "Algorithm"
|
||||||
|
|
||||||
class AlgorithmID(DecimalParam, AlgoConfig):
|
# as in pySim/esim/asn1/saip/PE_Definitions-3.3.1.asn
|
||||||
algo_config_key = 'algorithmID'
|
value_map = {
|
||||||
allow_len = 1
|
"Milenage" : 1,
|
||||||
example_input = 1 # Milenage
|
"TUAK" : 2,
|
||||||
|
"usim-test" : 3,
|
||||||
|
}
|
||||||
|
example_input = "Milenage"
|
||||||
default_source = param_source.ConstantSource
|
default_source = param_source.ConstantSource
|
||||||
|
|
||||||
|
algo_config_key = 'algorithmID'
|
||||||
|
|
||||||
|
# EnumParam.validate_val() returns the int values from value_map
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_val(cls, val):
|
def get_values_from_pes(cls, pes: ProfileElementSequence):
|
||||||
val = super().validate_val(val)
|
# return enum names, not raw values.
|
||||||
val = int(val)
|
# use of super(): this intends to call AlgoConfig.get_values_from_pes() so that the cls argument is this cls
|
||||||
valid = (1, 2, 3)
|
# here (AlgorithmID); i.e. AlgoConfig.get_values_from_pes(pes) doesn't work, because AlgoConfig needs to look up
|
||||||
if val not in valid:
|
# cls.algo_config_key.
|
||||||
raise ValueError(f'Invalid algorithmID {val!r}, must be one of {valid}')
|
for d in super(cls, cls).get_values_from_pes(pes):
|
||||||
return val
|
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):
|
class K(BinaryParam, AlgoConfig):
|
||||||
"""use validate_val() from BinaryParam, and apply_val() from AlgoConfig"""
|
"""use validate_val() from BinaryParam, and apply_val() from AlgoConfig"""
|
||||||
|
|||||||
Reference in New Issue
Block a user