mirror of
https://gitea.osmocom.org/sim-card/pysim.git
synced 2026-03-26 15:28:35 +03:00
filesystem: Maintain a 'service' attribute for all files on a card
This can be populated by card profiles with the SST/IST/UST service that is associated with the file. Change-Id: I3b3f74b691368fa09967ecb377a9f7a6d8af7869
This commit is contained in:
@@ -34,7 +34,7 @@ import cmd2
|
|||||||
from cmd2 import CommandSet, with_default_category, with_argparser
|
from cmd2 import CommandSet, with_default_category, with_argparser
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from typing import cast, Optional, Iterable, List, Dict, Tuple
|
from typing import cast, Optional, Iterable, List, Dict, Tuple, Union
|
||||||
|
|
||||||
from smartcard.util import toBytes
|
from smartcard.util import toBytes
|
||||||
|
|
||||||
@@ -44,6 +44,10 @@ from pySim.exceptions import *
|
|||||||
from pySim.jsonpath import js_path_find, js_path_modify
|
from pySim.jsonpath import js_path_find, js_path_modify
|
||||||
from pySim.commands import SimCardCommands
|
from pySim.commands import SimCardCommands
|
||||||
|
|
||||||
|
# int: a single service is associated with this file
|
||||||
|
# list: any of the listed services requires this file
|
||||||
|
# tuple: logical-and of the listed services requires this file
|
||||||
|
CardFileService = Union[int, List[int], Tuple[int, ...]]
|
||||||
|
|
||||||
class CardFile(object):
|
class CardFile(object):
|
||||||
"""Base class for all objects in the smart card filesystem.
|
"""Base class for all objects in the smart card filesystem.
|
||||||
@@ -53,7 +57,8 @@ class CardFile(object):
|
|||||||
RESERVED_FIDS = ['3f00']
|
RESERVED_FIDS = ['3f00']
|
||||||
|
|
||||||
def __init__(self, fid: str = None, sfid: str = None, name: str = None, desc: str = None,
|
def __init__(self, fid: str = None, sfid: str = None, name: str = None, desc: str = None,
|
||||||
parent: Optional['CardDF'] = None, profile: Optional['CardProfile'] = None):
|
parent: Optional['CardDF'] = None, profile: Optional['CardProfile'] = None,
|
||||||
|
service: Optional[CardFileService] = None):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
fid : File Identifier (4 hex digits)
|
fid : File Identifier (4 hex digits)
|
||||||
@@ -62,6 +67,7 @@ class CardFile(object):
|
|||||||
desc : Description of the file
|
desc : Description of the file
|
||||||
parent : Parent CardFile object within filesystem hierarchy
|
parent : Parent CardFile object within filesystem hierarchy
|
||||||
profile : Card profile that this file should be part of
|
profile : Card profile that this file should be part of
|
||||||
|
service : Service (SST/UST/IST) associated with the file
|
||||||
"""
|
"""
|
||||||
if not isinstance(self, CardADF) and fid == None:
|
if not isinstance(self, CardADF) and fid == None:
|
||||||
raise ValueError("fid is mandatory")
|
raise ValueError("fid is mandatory")
|
||||||
@@ -75,6 +81,7 @@ class CardFile(object):
|
|||||||
if self.parent and self.parent != self and self.fid:
|
if self.parent and self.parent != self and self.fid:
|
||||||
self.parent.add_file(self)
|
self.parent.add_file(self)
|
||||||
self.profile = profile
|
self.profile = profile
|
||||||
|
self.service = service
|
||||||
self.shell_commands = [] # type: List[CommandSet]
|
self.shell_commands = [] # type: List[CommandSet]
|
||||||
|
|
||||||
# Note: the basic properties (fid, name, ect.) are verified when
|
# Note: the basic properties (fid, name, ect.) are verified when
|
||||||
@@ -207,6 +214,28 @@ class CardFile(object):
|
|||||||
return self.parent.get_profile()
|
return self.parent.get_profile()
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def should_exist_for_services(self, services: List[int]):
|
||||||
|
"""Assuming the provided list of activated services, should this file exist and be activated?."""
|
||||||
|
if self.service is None:
|
||||||
|
return None
|
||||||
|
elif isinstance(self.service, int):
|
||||||
|
# a single service determines the result
|
||||||
|
return self.service in services
|
||||||
|
elif isinstance(self.service, list):
|
||||||
|
# any of the services active -> true
|
||||||
|
for s in self.service:
|
||||||
|
if s in services:
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
elif isinstance(self.service, tuple):
|
||||||
|
# all of the services active -> true
|
||||||
|
for s in self.service:
|
||||||
|
if not s in services:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise ValueError("self.service must be either int or list or tuple")
|
||||||
|
|
||||||
|
|
||||||
class CardDF(CardFile):
|
class CardDF(CardFile):
|
||||||
"""DF (Dedicated File) in the smart card filesystem. Those are basically sub-directories."""
|
"""DF (Dedicated File) in the smart card filesystem. Those are basically sub-directories."""
|
||||||
@@ -223,10 +252,27 @@ class CardDF(CardFile):
|
|||||||
super().__init__(**kwargs)
|
super().__init__(**kwargs)
|
||||||
self.children = dict()
|
self.children = dict()
|
||||||
self.shell_commands = [self.ShellCommands()]
|
self.shell_commands = [self.ShellCommands()]
|
||||||
|
# dict of CardFile affected by service(int), indexed by service
|
||||||
|
self.files_by_service = {}
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return "DF(%s)" % (super().__str__())
|
return "DF(%s)" % (super().__str__())
|
||||||
|
|
||||||
|
def _add_file_services(self, child):
|
||||||
|
"""Add a child (DF/EF) to the files_by_services of the parent."""
|
||||||
|
if not child.service:
|
||||||
|
return
|
||||||
|
if isinstance(child.service, int):
|
||||||
|
self.files_by_service.setdefault(child.service, []).append(child)
|
||||||
|
elif isinstance(child.service, list):
|
||||||
|
for service in child.service:
|
||||||
|
self.files_by_service.setdefault(service, []).append(child)
|
||||||
|
elif isinstance(child.service, tuple):
|
||||||
|
for service in child.service:
|
||||||
|
self.files_by_service.setdefault(service, []).append(child)
|
||||||
|
else:
|
||||||
|
raise ValueError
|
||||||
|
|
||||||
def add_file(self, child: CardFile, ignore_existing: bool = False):
|
def add_file(self, child: CardFile, ignore_existing: bool = False):
|
||||||
"""Add a child (DF/EF) to this DF.
|
"""Add a child (DF/EF) to this DF.
|
||||||
Args:
|
Args:
|
||||||
@@ -256,6 +302,7 @@ class CardDF(CardFile):
|
|||||||
"File with given name %s already exists in %s" % (child.name, self))
|
"File with given name %s already exists in %s" % (child.name, self))
|
||||||
self.children[child.fid] = child
|
self.children[child.fid] = child
|
||||||
child.parent = self
|
child.parent = self
|
||||||
|
self._add_file_services(child)
|
||||||
|
|
||||||
def add_files(self, children: Iterable[CardFile], ignore_existing: bool = False):
|
def add_files(self, children: Iterable[CardFile], ignore_existing: bool = False):
|
||||||
"""Add a list of child (DF/EF) to this DF
|
"""Add a list of child (DF/EF) to this DF
|
||||||
@@ -519,7 +566,7 @@ class TransparentEF(CardEF):
|
|||||||
self._cmd.poutput_json(data)
|
self._cmd.poutput_json(data)
|
||||||
|
|
||||||
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None, parent: CardDF = None,
|
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None, parent: CardDF = None,
|
||||||
size={1, None}):
|
size={1, None}, **kwargs):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
fid : File Identifier (4 hex digits)
|
fid : File Identifier (4 hex digits)
|
||||||
@@ -529,7 +576,7 @@ class TransparentEF(CardEF):
|
|||||||
parent : Parent CardFile object within filesystem hierarchy
|
parent : Parent CardFile object within filesystem hierarchy
|
||||||
size : tuple of (minimum_size, recommended_size)
|
size : tuple of (minimum_size, recommended_size)
|
||||||
"""
|
"""
|
||||||
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, **kwargs)
|
||||||
self._construct = None
|
self._construct = None
|
||||||
self._tlv = None
|
self._tlv = None
|
||||||
self.size = size
|
self.size = size
|
||||||
@@ -654,8 +701,8 @@ class LinFixedEF(CardEF):
|
|||||||
class ShellCommands(CommandSet):
|
class ShellCommands(CommandSet):
|
||||||
"""Shell commands specific for Linear Fixed EFs."""
|
"""Shell commands specific for Linear Fixed EFs."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self, **kwargs):
|
||||||
super().__init__()
|
super().__init__(**kwargs)
|
||||||
|
|
||||||
read_rec_parser = argparse.ArgumentParser()
|
read_rec_parser = argparse.ArgumentParser()
|
||||||
read_rec_parser.add_argument(
|
read_rec_parser.add_argument(
|
||||||
@@ -777,7 +824,7 @@ class LinFixedEF(CardEF):
|
|||||||
self._cmd.poutput_json(data)
|
self._cmd.poutput_json(data)
|
||||||
|
|
||||||
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None,
|
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None,
|
||||||
parent: Optional[CardDF] = None, rec_len={1, None}):
|
parent: Optional[CardDF] = None, rec_len={1, None}, **kwargs):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
fid : File Identifier (4 hex digits)
|
fid : File Identifier (4 hex digits)
|
||||||
@@ -787,7 +834,7 @@ class LinFixedEF(CardEF):
|
|||||||
parent : Parent CardFile object within filesystem hierarchy
|
parent : Parent CardFile object within filesystem hierarchy
|
||||||
rec_len : set of {minimum_length, recommended_length}
|
rec_len : set of {minimum_length, recommended_length}
|
||||||
"""
|
"""
|
||||||
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, **kwargs)
|
||||||
self.rec_len = rec_len
|
self.rec_len = rec_len
|
||||||
self.shell_commands = [self.ShellCommands()]
|
self.shell_commands = [self.ShellCommands()]
|
||||||
self._construct = None
|
self._construct = None
|
||||||
@@ -908,9 +955,8 @@ class CyclicEF(LinFixedEF):
|
|||||||
# we don't really have any special support for those; just recycling LinFixedEF here
|
# we don't really have any special support for those; just recycling LinFixedEF here
|
||||||
|
|
||||||
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None, parent: CardDF = None,
|
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None, parent: CardDF = None,
|
||||||
rec_len={1, None}):
|
rec_len={1, None}, **kwargs):
|
||||||
super().__init__(fid=fid, sfid=sfid, name=name,
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, rec_len=rec_len, **kwargs)
|
||||||
desc=desc, parent=parent, rec_len=rec_len)
|
|
||||||
|
|
||||||
|
|
||||||
class TransRecEF(TransparentEF):
|
class TransRecEF(TransparentEF):
|
||||||
@@ -924,7 +970,7 @@ class TransRecEF(TransparentEF):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, fid: str, rec_len: int, sfid: str = None, name: str = None, desc: str = None,
|
def __init__(self, fid: str, rec_len: int, sfid: str = None, name: str = None, desc: str = None,
|
||||||
parent: Optional[CardDF] = None, size={1, None}):
|
parent: Optional[CardDF] = None, size={1, None}, **kwargs):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
fid : File Identifier (4 hex digits)
|
fid : File Identifier (4 hex digits)
|
||||||
@@ -935,7 +981,7 @@ class TransRecEF(TransparentEF):
|
|||||||
rec_len : Length of the fixed-length records within transparent EF
|
rec_len : Length of the fixed-length records within transparent EF
|
||||||
size : tuple of (minimum_size, recommended_size)
|
size : tuple of (minimum_size, recommended_size)
|
||||||
"""
|
"""
|
||||||
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, size=size)
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, size=size, **kwargs)
|
||||||
self.rec_len = rec_len
|
self.rec_len = rec_len
|
||||||
|
|
||||||
def decode_record_hex(self, raw_hex_data: str) -> dict:
|
def decode_record_hex(self, raw_hex_data: str) -> dict:
|
||||||
@@ -1112,7 +1158,7 @@ class BerTlvEF(CardEF):
|
|||||||
self._cmd.poutput(data)
|
self._cmd.poutput(data)
|
||||||
|
|
||||||
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None, parent: CardDF = None,
|
def __init__(self, fid: str, sfid: str = None, name: str = None, desc: str = None, parent: CardDF = None,
|
||||||
size={1, None}):
|
size={1, None}, **kwargs):
|
||||||
"""
|
"""
|
||||||
Args:
|
Args:
|
||||||
fid : File Identifier (4 hex digits)
|
fid : File Identifier (4 hex digits)
|
||||||
@@ -1122,7 +1168,7 @@ class BerTlvEF(CardEF):
|
|||||||
parent : Parent CardFile object within filesystem hierarchy
|
parent : Parent CardFile object within filesystem hierarchy
|
||||||
size : tuple of (minimum_size, recommended_size)
|
size : tuple of (minimum_size, recommended_size)
|
||||||
"""
|
"""
|
||||||
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent)
|
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, **kwargs)
|
||||||
self._construct = None
|
self._construct = None
|
||||||
self.size = size
|
self.size = size
|
||||||
self.shell_commands = [self.ShellCommands()]
|
self.shell_commands = [self.ShellCommands()]
|
||||||
|
|||||||
Reference in New Issue
Block a user