Attention is currently required from: pespin.
osmith has posted comments on this change by pespin. ( https://gerrit.osmocom.org/c/osmo-hnbgw/+/40176?usp=email )
Change subject: context_map_sccp: Queue RUA->SCCP RANAP msgs while in SCCP WAIT_CC state
......................................................................
Patch Set 4: Code-Review+1
--
To view, visit https://gerrit.osmocom.org/c/osmo-hnbgw/+/40176?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: comment
Gerrit-Project: osmo-hnbgw
Gerrit-Branch: master
Gerrit-Change-Id: I307ded905901421f8228fab720b3989a2f94412b
Gerrit-Change-Number: 40176
Gerrit-PatchSet: 4
Gerrit-Owner: pespin <pespin(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: osmith <osmith(a)sysmocom.de>
Gerrit-Attention: pespin <pespin(a)sysmocom.de>
Gerrit-Comment-Date: Mon, 05 May 2025 07:49:24 +0000
Gerrit-HasComments: No
Gerrit-Has-Labels: Yes
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/40209?usp=email )
Change subject: personalization audit: by default audit all SD keys
......................................................................
personalization audit: by default audit all SD keys
Audit also all Security Domain KVN that we have *not* created
ConfigurableParameter subclasses for.
For example, SCP80 has reserved kvn 0x01..0x0f, but we offer only
Scp80Kvn01, Scp80Kvn02, Scp80Kvn03. So we would not show kvn
0x03..0x0f in an audit.
This patch includes audits of all SD key kvn there may be in the UPP.
This will help to spot SD keys that may already be present in a UPP
template, with unexpected / unusual kvn.
Change-Id: Icaf6f7b589f117868633c0968a99f2f0252cf612
---
M pySim/esim/saip/personalization.py
1 file changed, 23 insertions(+), 2 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/09/40209/1
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index 3919e79..6828ada 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -1173,11 +1173,18 @@
"""
@classmethod
- def from_der(cls, der: bytes, params: List):
+ def from_der(cls, der: bytes, params: List, additional_sd_keys=True):
'''return a dict of parameter name and set of parameter values found in a DER encoded profile.
Read all parameters listed in params. This calls only classmethods, so each entry in params can either be a class or
an instance of a class, of a (non-abstract) ConfigurableParameter subclass. For example, params = [Imsi, ] is
- equivalent to params = [Imsi(), ].'''
+ equivalent to params = [Imsi(), ].
+
+ For additional_sd_keys=True, audit also all Security Domain KVN that there are *no* ConfigurableParameter
+ subclasses for. For example, SCP80 has reserved kvn 0x01..0x0f, but we offer only Scp80Kvn01, Scp80Kvn02,
+ Scp80Kvn03. So we would not show kvn 0x03..0x0f in an audit. additional_sd_keys=True includes audits of all SD
+ key KVN there may be in the UPP. This helps to spot SD keys that may already be present in a UPP template, with
+ unexpected / unusual kvn.
+ '''
upp_audit = cls()
upp_audit['der_size'] = set((len(der), ))
@@ -1193,6 +1200,20 @@
upp_audit.add_values(valdict)
except (TypeError, ValueError) as e:
raise ValueError(f'Error during audit for parameter {key}: {e}') from e
+
+ if not additional_sd_keys:
+ return upp_audit
+
+ # additional_sd_keys
+ for pe in pes.pe_list:
+ if pe.type != 'securityDomain':
+ continue
+ assert isinstance(pe, ProfileElementSD)
+
+ for key in pe.keys:
+ audit_key = f'SdKey_KVN{key.key_version_number:02x}_ID{key.key_identifier:02x}'
+ audit_val = f'{key.key_components!r} {key.key_usage_qualifier!r}'
+ upp_audit[audit_key] = audit_val
return upp_audit
def get_single_val(self, param, validate=True, allow_absent=False, absent_val=None):
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/40209?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: Icaf6f7b589f117868633c0968a99f2f0252cf612
Gerrit-Change-Number: 40209
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/40208?usp=email )
Change subject: personalization: implement UppAudit and BatchAudit
......................................................................
personalization: implement UppAudit and BatchAudit
Change-Id: Iaab336ca91b483ecdddd5c6c8e08dc475dc6bd0a
---
M pySim/esim/saip/personalization.py
1 file changed, 212 insertions(+), 0 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/08/40208/1
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index 7217af3..3919e79 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -277,6 +277,13 @@
and ((not blacklist) or (c not in blacklist)))
)
+ @classmethod
+ def is_super_of(cls, other_class):
+ try:
+ return issubclass(other_class, cls)
+ except TypeError:
+ return False
+
class DecimalParam(ConfigurableParameter):
"""Decimal digits. The input value may be a string of decimal digits like '012345', or an int. The output of
validate_val() is a string with only decimal digits 0-9, in the required length with leading zeros if necessary.
@@ -1156,3 +1163,208 @@
f' (input_value={p.param.input_value!r} value={p.param.value!r})') from e
yield pes
+
+
+class UppAudit(dict):
+ """
+ Key-value pairs collected from a single UPP DER or PES.
+
+ UppAudit itself is a dict, callers may use the standard python dict API to access key-value pairs read from the UPP.
+ """
+
+ @classmethod
+ def from_der(cls, der: bytes, params: List):
+ '''return a dict of parameter name and set of parameter values found in a DER encoded profile.
+ Read all parameters listed in params. This calls only classmethods, so each entry in params can either be a class or
+ an instance of a class, of a (non-abstract) ConfigurableParameter subclass. For example, params = [Imsi, ] is
+ equivalent to params = [Imsi(), ].'''
+ upp_audit = cls()
+
+ upp_audit['der_size'] = set((len(der), ))
+
+ pes = ProfileElementSequence.from_der(der)
+ for param in params:
+ key = param.get_name()
+ if key in upp_audit:
+ raise ValueError(f'UPP audit: there seem to be two conflicting parameters with the name {key!r}: '
+ + ', '.join(f"{param.get_name()}={param.__name__}" for param in params))
+ try:
+ for valdict in param.get_values_from_pes(pes):
+ upp_audit.add_values(valdict)
+ except (TypeError, ValueError) as e:
+ raise ValueError(f'Error during audit for parameter {key}: {e}') from e
+ return upp_audit
+
+ def get_single_val(self, param, validate=True, allow_absent=False, absent_val=None):
+ """
+ Return the audit's value for the given ConfigurableParameter class.
+ Any kind of value may occur multiple times in a profile. When all of these agree to the same unambiguous value,
+ return that value. When they do not agree, raise a ValueError.
+ """
+ cp = None
+ if ConfigurableParameter.is_super_of(param):
+ cp = param
+ key = param.name
+ else:
+ key = param
+ assert isinstance(key, str)
+ v = self.get(key)
+ if v is None and allow_absent:
+ return absent_val
+ if not isinstance(v, set):
+ raise ValueError(f'audit value should be a set(), got {v!r}')
+ if len(v) != 1:
+ raise ValueError(f'expected a single value for {key}, got {v!r}')
+ v = tuple(v)[0]
+ if validate and cp:
+ # run value by the ConfigurableParameter's validation.
+ # (do not use the returned value, because the returned value is encoded for a PES)
+ cp.validate_val(v)
+ return v
+
+ @staticmethod
+ def audit_val_to_str(v):
+ """
+ Usually, we want to see a single value in an audit. Still, to be able to collect multiple ambiguous values,
+ audit values are always python sets. Turn it into a nice string representation: only the value when it is
+ unambiguous, otherwise a list of the ambiguous values.
+ A value may also be completely absent, then return 'not present'.
+ """
+ def try_single_val(w):
+ 'change single-entry sets to just the single value'
+ if isinstance(w, set):
+ if len(w) == 1:
+ return tuple(w)[0]
+ if len(w) == 0:
+ return None
+ return w
+
+ v = try_single_val(v)
+ if isinstance(v, bytes):
+ v = bytes_to_hexstr(v)
+ if v is None:
+ return 'not present'
+ return str(v)
+
+ def get_val_str(self, key):
+ """Return a string of the value stored for the given key"""
+ return UppAudit.audit_val_to_str(self.get(key))
+
+ def add_values(self, src:dict):
+ """self and src are both a dict of sets.
+ For example from
+ self == { 'a': set((123,)) }
+ and
+ src == { 'a': set((456,)), 'b': set((789,)) }
+ then after this function call:
+ self == { 'a': set((123, 456,)), 'b': set((789,)) }
+ """
+ assert isinstance(src, dict)
+ for key, srcvalset in src.items():
+ dstvalset = self.get(key)
+ if dstvalset is None:
+ dstvalset = set()
+ self[key] = dstvalset
+ dstvalset.add(srcvalset)
+
+ def __str__(self):
+ return '\n'.join(f'{key}: {self.get_val_str(key)}' for key in sorted(self.keys()))
+
+class BatchAudit(list):
+ """
+ Collect UppAudit instances for a batch of UPP, for example from a personalization.BatchPersonalization.
+ Produce an output CSV.
+
+ Usage example:
+
+ ba = BatchAudit(params=(personalization.Iccid, ))
+ for upp_der in upps:
+ ba.add_audit(upp_der)
+ print(ba.summarize())
+
+ with open('output.csv', 'wb') as csv_data:
+ csv_str = io.TextIOWrapper(csv_data, 'utf-8', newline='')
+ csv.writer(csv_str).writerows( ba.to_csv_rows() )
+ csv_str.flush()
+
+ BatchAudit itself is a list, callers may use the standard python list API to access the UppAudit instances.
+ """
+
+ def __init__(self, params:List=None):
+ if params is None:
+ params = ConfigurableParameter.get_all_implementations()
+ self.params = params
+
+ def add_audit(self, upp_der:bytes):
+ audit = UppAudit.from_der(upp_der, self.params)
+ self.append(audit)
+ return audit
+
+ def summarize(self):
+ batch_audit = UppAudit()
+
+ audits = self
+
+ if len(audits) > 2:
+ val_sep = ', ..., '
+ else:
+ val_sep = ', '
+
+ first_audit = None
+ last_audit = None
+ if len(audits) >= 1:
+ first_audit = audits[0]
+ if len(audits) >= 2:
+ last_audit = audits[-1]
+
+ if first_audit:
+ if last_audit:
+ for key in first_audit.keys():
+ first_val = first_audit.get_val_str(key)
+ last_val = last_audit.get_val_str(key)
+
+ if first_val == last_val:
+ val = first_val
+ else:
+ val_sep_with_newline = f"{val_sep.rstrip()}\n{' ' * (len(key) + 2)}"
+ val = val_sep_with_newline.join((first_val, last_val))
+ batch_audit[key] = val
+ else:
+ batch_audit.update(first_audit)
+
+ return batch_audit
+
+ def to_csv_rows(self, headers=True):
+ '''generator that yields all audits' values as rows, useful feed to a csv.writer.'''
+ params = tuple(sorted(self.params, key=lambda param: param.get_name()))
+ if headers:
+ yield (p.get_name() for p in params)
+
+ for audit in self:
+ yield (audit.get_single_val(p, allow_absent=True, absent_val="") for p in params)
+
+def bytes_to_hexstr(b:bytes, sep=''):
+ return sep.join(f'{x:02x}' for x in b)
+
+def esim_profile_introspect(upp):
+ pes = ProfileElementSequence.from_der(upp.read())
+ d = {}
+ d['upp'] = repr(pes)
+
+ def show_bytes_as_hexdump(item):
+ if isinstance(item, bytes):
+ return bytes_to_hexstr(item)
+ if isinstance(item, list):
+ return list(show_bytes_as_hexdump(i) for i in item)
+ if isinstance(item, tuple):
+ return tuple(show_bytes_as_hexdump(i) for i in item)
+ if isinstance(item, dict):
+ d = {}
+ for k, v in item.items():
+ d[k] = show_bytes_as_hexdump(v)
+ return d
+ return item
+
+ l = list((pe.type, show_bytes_as_hexdump(pe.decoded)) for pe in pes)
+ d['pp'] = pprint.pformat(l, width=120)
+ return d
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/40208?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: Iaab336ca91b483ecdddd5c6c8e08dc475dc6bd0a
Gerrit-Change-Number: 40208
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/40203?usp=email )
Change subject: personalization: fix SdKey.apply_val() implementation
......................................................................
personalization: fix SdKey.apply_val() implementation
'securityDomain' elements are decoded to ProfileElementSD instances,
which keep higher level representations of the key data apart from the
decoded[] lists.
So far, apply_val() was dropping binary values in decoded[], which does
not work, because ProfileElementSD._pre_encode() overwrites
self.decoded[] from the higher level representation.
Implement using
- ProfileElementSD.find_key() and SecurityDomainKeyComponent to modify
an exsiting entry, or
- ProfileElementSD.add_key() to create a new entry.
Before this patch, SdKey parameters seemed to patch PES successfully,
but their modifications did not end up in the encoded DER.
(BTW, this does not fix any other errors that may still be present in
the various SdKey subclasses, patches coming up.)
Related: SYS#6768
Change-Id: I07dfc378705eba1318e9e8652796cbde106c6a52
---
M pySim/esim/saip/__init__.py
M pySim/esim/saip/personalization.py
2 files changed, 41 insertions(+), 27 deletions(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/03/40203/1
diff --git a/pySim/esim/saip/__init__.py b/pySim/esim/saip/__init__.py
index 21f44ef..0b3d302 100644
--- a/pySim/esim/saip/__init__.py
+++ b/pySim/esim/saip/__init__.py
@@ -991,6 +991,13 @@
'keyVersionNumber': bytes([self.key_version_number]),
'keyComponents': [k.to_saip_dict() for k in self.key_components]}
+ def get_key_component(self, key_type):
+ for kc in self.key_components:
+ if kc.key_type == key_type:
+ return kc.key_data
+ return None
+
+
class ProfileElementSD(ProfileElement):
"""Class representing a securityDomain ProfileElement."""
type = 'securityDomain'
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index e3ded68..0eb0671 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -24,8 +24,10 @@
from osmocom.tlv import camel_to_snake
from osmocom.utils import hexstr
from pySim.utils import enc_iccid, dec_iccid, enc_imsi, dec_imsi, h2b, b2h, rpad, sanitize_iccid, all_subclasses_of
-from pySim.esim.saip import ProfileElement, ProfileElementSequence
from pySim.esim.saip import param_source
+from pySim.esim.saip import ProfileElement, ProfileElementSD, ProfileElementSequence
+from pySim.esim.saip import SecurityDomainKey, SecurityDomainKeyComponent
+from pySim.global_platform import KeyUsageQualifier, KeyType
def unrpad(s: hexstr, c='f') -> hexstr:
return hexstr(s.rstrip(c))
@@ -498,36 +500,41 @@
default_source = param_source.RandomHexDigitSource
@classmethod
- def _apply_sd(cls, pe: ProfileElement, value):
- assert pe.type == 'securityDomain'
- for key in pe.decoded['keyList']:
- if key['keyIdentifier'][0] == cls.key_id and key['keyVersionNumber'][0] == cls.kvn:
- assert len(key['keyComponents']) == 1
- key['keyComponents'][0]['keyData'] = value
- return
- # Could not find matching key to patch, create a new one
- key = {
- 'keyUsageQualifier': bytes([cls.key_usage_qual]),
- 'keyIdentifier': bytes([cls.key_id]),
- 'keyVersionNumber': bytes([cls.kvn]),
- 'keyComponents': [
- { 'keyType': bytes([cls.key_type]), 'keyData': value },
- ]
- }
- pe.decoded['keyList'].append(key)
+ def apply_val(cls, pes: ProfileElementSequence, val):
+ set_components = [ SecurityDomainKeyComponent(cls.key_type, val) ]
- @classmethod
- def apply_val(cls, pes: ProfileElementSequence, value):
- for pe in pes.get_pes_for_type('securityDomain'):
- cls._apply_sd(pe, value)
+ for pe in pes.pe_list:
+ if pe.type != 'securityDomain':
+ continue
+ assert isinstance(pe, ProfileElementSD)
+
+ key = pe.find_key(key_version_number=cls.kvn, key_id=cls.key_id)
+ if not key:
+ # Could not find matching key to patch, create a new one
+ key = SecurityDomainKey(
+ key_version_number=cls.kvn,
+ key_id=cls.key_id,
+ key_usage_qualifier=KeyUsageQualifier.build(cls.key_usage_qual),
+ key_components=set_components,
+ )
+ pe.add_key(key)
+ else:
+ print(f'{key.key_usage_qualifier=!r}')
+ key.key_components = set_components
@classmethod
def get_values_from_pes(cls, pes: ProfileElementSequence):
- for pe in pes.get_pes_for_type('securityDomain'):
- for key in pe.decoded['keyList']:
- if key['keyIdentifier'][0] == cls.key_id and key['keyVersionNumber'][0] == cls.kvn:
- if len(key['keyComponents']) >= 1:
- yield { cls.name: b2h(key['keyComponents'][0]['keyData']) }
+ for pe in pes.pe_list:
+ if pe.type != 'securityDomain':
+ continue
+ assert isinstance(pe, ProfileElementSD)
+
+ key = pe.find_key(key_version_number=cls.kvn, key_id=cls.key_id)
+ if not key:
+ continue
+ kc = key.get_key_component(cls.key_type)
+ if kc:
+ yield { cls.name: b2h(kc) }
class SdKeyScp80_01(SdKey):
kvn = 0x01
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/40203?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: I07dfc378705eba1318e9e8652796cbde106c6a52
Gerrit-Change-Number: 40203
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>
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>
neels has uploaded this change for review. ( https://gerrit.osmocom.org/c/pysim/+/40202?usp=email )
Change subject: personalization: add get_typical_input_len() to ConfigurableParameter
......................................................................
personalization: add get_typical_input_len() to ConfigurableParameter
The aim is to tell a user interface how wide an input text field should
be chosen to be convenient -- ideally showing the entire value in all
cases, but not too huge for fields that have no sane size limit.
Change-Id: I2568a032167a10517d4d75d8076a747be6e21890
---
M pySim/esim/saip/personalization.py
1 file changed, 18 insertions(+), 1 deletion(-)
git pull ssh://gerrit.osmocom.org:29418/pysim refs/changes/02/40202/1
diff --git a/pySim/esim/saip/personalization.py b/pySim/esim/saip/personalization.py
index 1ce420a..e3ded68 100644
--- a/pySim/esim/saip/personalization.py
+++ b/pySim/esim/saip/personalization.py
@@ -259,6 +259,14 @@
return (min(vals), max(vals))
@classmethod
+ def get_typical_input_len(cls):
+ '''return a good length to use as the visible width of a user interface input field.
+ May be overridden by subclasses.
+ This default implementation returns the maximum allowed value length -- a good fit for most subclasses.
+ '''
+ return cls.get_len_range()[1] or 16
+
+ @classmethod
def get_all_implementations(cls, blacklist=None, allow_abstract=False):
# return a set() so that multiple inheritance does not return dups
return set(c
@@ -267,7 +275,6 @@
and ((not blacklist) or (c not in blacklist)))
)
-
class DecimalParam(ConfigurableParameter):
"""Decimal digits. The input value may be a string of decimal digits like '012345', or an int. The output of
validate_val() is a string with only decimal digits 0-9, in the required length with leading zeros if necessary.
@@ -338,6 +345,16 @@
val = super().validate_val(val)
return bytes(val)
+ @classmethod
+ def get_typical_input_len(cls):
+ # override to return twice the length, because of hex digits.
+ min_len, max_len = cls.get_len_range()
+ if max_len is None:
+ return None
+ # two hex characters per value octet.
+ # (maybe *3 to also allow for spaces?)
+ return max_len * 2
+
class EnumParam(ConfigurableParameter):
value_map = {
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/40202?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: I2568a032167a10517d4d75d8076a747be6e21890
Gerrit-Change-Number: 40202
Gerrit-PatchSet: 1
Gerrit-Owner: neels <nhofmeyr(a)sysmocom.de>