blob: 2e98d7d017c565075a0bb2359de80a57e28c74dc [file] [log] [blame]
Philipp Maier2b11c322021-03-17 12:37:39 +01001# coding=utf-8
Harald Welte90d3b972021-04-03 08:56:21 +02002"""Abstraction of card related data that can be queried from external source."""
Philipp Maier2b11c322021-03-17 12:37:39 +01003
Harald Welte90d3b972021-04-03 08:56:21 +02004# (C) 2021 by Sysmocom s.f.m.c. GmbH
5# All Rights Reserved
6#
7# Author: Philipp Maier
8#
9# This program is free software: you can redistribute it and/or modify
10# it under the terms of the GNU General Public License as published by
11# the Free Software Foundation, either version 2 of the License, or
12# (at your option) any later version.
13#
14# This program is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17# GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with this program. If not, see <http://www.gnu.org/licenses/>.
Philipp Maier2b11c322021-03-17 12:37:39 +010021
Harald Welte90d3b972021-04-03 08:56:21 +020022from typing import List, Dict, Optional
Philipp Maier2b11c322021-03-17 12:37:39 +010023
24import csv
25
Harald Welte4442b3d2021-04-03 09:00:16 +020026card_key_providers = [] # type: List[CardData]
Philipp Maier2b11c322021-03-17 12:37:39 +010027
Harald Welte4442b3d2021-04-03 09:00:16 +020028class CardKeyProvider(object):
Philipp Maier2b11c322021-03-17 12:37:39 +010029
Philipp Maier46f09af2021-03-25 20:24:27 +010030 VALID_FIELD_NAMES = ['ICCID', 'ADM1', 'IMSI', 'PIN1', 'PIN2', 'PUK1', 'PUK2']
Philipp Maier2b11c322021-03-17 12:37:39 +010031
32 # check input parameters, but do nothing concrete yet
Harald Welte90d3b972021-04-03 08:56:21 +020033 def get_data(self, fields:List[str]=[], key:str='ICCID', value:str="") -> Dict[str,str]:
Philipp Maier2b11c322021-03-17 12:37:39 +010034 """abstract implementation of get_data that only verifies the function parameters"""
35
36 for f in fields:
37 if (f not in self.VALID_FIELD_NAMES):
38 raise ValueError("Requested field name '%s' is not a valid field name, valid field names are: %s" %
39 (f, str(self.VALID_FIELD_NAMES)))
40
41 if (key not in self.VALID_FIELD_NAMES):
42 raise ValueError("Key field name '%s' is not a valid field name, valid field names are: %s" %
43 (key, str(self.VALID_FIELD_NAMES)))
44
45 return {}
46
Harald Welte90d3b972021-04-03 08:56:21 +020047 def get_field(self, field:str, key:str='ICCID', value:str="") -> Optional[str]:
Philipp Maier2b11c322021-03-17 12:37:39 +010048 """get a single field from CSV file using a specified key/value pair"""
49 fields = [field]
50 result = self.get(fields, key, value)
51 return result.get(field)
52
Harald Welte90d3b972021-04-03 08:56:21 +020053 def get(self, fields:List[str], key:str, value:str) -> Dict[str,str]:
54 """get fields from CSV file using a specified key/value pair"""
55 pass
Philipp Maier2b11c322021-03-17 12:37:39 +010056
Harald Welte4442b3d2021-04-03 09:00:16 +020057class CardKeyProviderCsv(CardKeyProvider):
Philipp Maier2b11c322021-03-17 12:37:39 +010058 """card data class that allows the user to query against a specified CSV file"""
59 csv_file = None
60 filename = None
61
Harald Welte90d3b972021-04-03 08:56:21 +020062 def __init__(self, filename:str):
Philipp Maier2b11c322021-03-17 12:37:39 +010063 self.csv_file = open(filename, 'r')
64 if not self.csv_file:
65 raise RuntimeError("Could not open CSV-File '%s'" % filename)
66 self.filename = filename
67
Harald Welte90d3b972021-04-03 08:56:21 +020068 def get(self, fields:List[str], key:str, value:str) -> Dict[str,str]:
Philipp Maier2b11c322021-03-17 12:37:39 +010069 """get fields from CSV file using a specified key/value pair"""
70 super().get_data(fields, key, value)
71
72 self.csv_file.seek(0)
73 cr = csv.DictReader(self.csv_file)
74 if not cr:
75 raise RuntimeError("Could not open DictReader for CSV-File '%s'" % self.filename)
76 cr.fieldnames = [ field.upper() for field in cr.fieldnames ]
77
78 rc = {}
79 for row in cr:
80 if row[key] == value:
81 for f in fields:
82 if f in row:
83 rc.update({f : row[f]})
84 else:
85 raise RuntimeError("CSV-File '%s' lacks column '%s'" %
86 (self.filename, f))
87 return rc
88
89
Harald Welte4442b3d2021-04-03 09:00:16 +020090def card_key_provider_register(provider:CardKeyProvider, provider_list=card_key_providers):
Philipp Maier2b11c322021-03-17 12:37:39 +010091 """Register a new card data provider"""
Harald Welte4442b3d2021-04-03 09:00:16 +020092 if not isinstance(provider, CardKeyProvider):
Philipp Maier2b11c322021-03-17 12:37:39 +010093 raise ValueError("provider is not a card data provier")
94 provider_list.append(provider)
95
96
Harald Welte4442b3d2021-04-03 09:00:16 +020097def card_key_provider_get(fields, key:str, value:str, provider_list=card_key_providers) -> Dict[str,str]:
Philipp Maier2b11c322021-03-17 12:37:39 +010098 """Query all registered card data providers"""
99 for p in provider_list:
Harald Welte4442b3d2021-04-03 09:00:16 +0200100 if not isinstance(p, CardKeyProvider):
Philipp Maier2b11c322021-03-17 12:37:39 +0100101 raise ValueError("provider list contains provider, which is not a card data provier")
102 result = p.get(fields, key, value)
103 if result:
104 return result
105 return {}
106
107
Harald Welte4442b3d2021-04-03 09:00:16 +0200108def card_key_provider_get_field(field:str, key:str, value:str, provider_list=card_key_providers) -> Optional[str]:
Philipp Maier2b11c322021-03-17 12:37:39 +0100109 """Query all registered card data providers for a single field"""
110 for p in provider_list:
Harald Welte4442b3d2021-04-03 09:00:16 +0200111 if not isinstance(p, CardKeyProvider):
Philipp Maier2b11c322021-03-17 12:37:39 +0100112 raise ValueError("provider list contains provider, which is not a card data provier")
113 result = p.get_field(field, key, value)
114 if result:
115 return result
116 return None
117