qolsys-controller 0.0.38__py3-none-any.whl → 0.0.62__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of qolsys-controller might be problematic. Click here for more details.
- qolsys_controller/controller.py +829 -20
- qolsys_controller/database/db.py +63 -25
- qolsys_controller/database/table.py +89 -60
- qolsys_controller/database/table_alarmedsensor.py +0 -2
- qolsys_controller/database/table_automation.py +0 -1
- qolsys_controller/database/table_country_locale.py +0 -1
- qolsys_controller/database/table_dashboard_msgs.py +1 -2
- qolsys_controller/database/table_dimmerlight.py +0 -1
- qolsys_controller/database/table_doorlock.py +1 -1
- qolsys_controller/database/table_eu_event.py +12 -4
- qolsys_controller/database/table_heat_map.py +0 -2
- qolsys_controller/database/table_history.py +4 -1
- qolsys_controller/database/table_iqremotesettings.py +0 -2
- qolsys_controller/database/table_iqrouter_network_config.py +0 -1
- qolsys_controller/database/table_iqrouter_user_device.py +0 -2
- qolsys_controller/database/table_master_slave.py +0 -1
- qolsys_controller/database/table_nest_device.py +0 -1
- qolsys_controller/database/table_output_rules.py +0 -1
- qolsys_controller/database/table_partition.py +0 -1
- qolsys_controller/database/table_pgm_outputs.py +0 -2
- qolsys_controller/database/table_powerg_device.py +25 -3
- qolsys_controller/database/table_qolsyssettings.py +0 -2
- qolsys_controller/database/table_scene.py +0 -2
- qolsys_controller/database/table_sensor.py +3 -2
- qolsys_controller/database/table_sensor_group.py +23 -0
- qolsys_controller/database/table_shades.py +0 -2
- qolsys_controller/database/table_smartsocket.py +0 -2
- qolsys_controller/database/table_state.py +0 -1
- qolsys_controller/database/table_tcc.py +0 -1
- qolsys_controller/database/table_thermostat.py +0 -1
- qolsys_controller/database/table_trouble_conditions.py +0 -2
- qolsys_controller/database/table_user.py +1 -2
- qolsys_controller/database/table_virtual_device.py +0 -2
- qolsys_controller/database/table_weather.py +0 -2
- qolsys_controller/database/table_zigbee_device.py +0 -1
- qolsys_controller/database/table_zwave_association_group.py +0 -1
- qolsys_controller/database/table_zwave_history.py +0 -1
- qolsys_controller/database/table_zwave_node.py +1 -1
- qolsys_controller/database/table_zwave_other.py +14 -2
- qolsys_controller/enum.py +44 -16
- qolsys_controller/enum_zwave.py +81 -36
- qolsys_controller/errors.py +9 -12
- qolsys_controller/mdns.py +7 -4
- qolsys_controller/mqtt_command.py +119 -0
- qolsys_controller/mqtt_command_queue.py +5 -4
- qolsys_controller/observable.py +2 -2
- qolsys_controller/panel.py +224 -143
- qolsys_controller/partition.py +129 -127
- qolsys_controller/pki.py +69 -97
- qolsys_controller/scene.py +30 -28
- qolsys_controller/settings.py +96 -50
- qolsys_controller/state.py +71 -33
- qolsys_controller/task_manager.py +8 -12
- qolsys_controller/users.py +25 -0
- qolsys_controller/utils_mqtt.py +8 -16
- qolsys_controller/weather.py +71 -0
- qolsys_controller/zone.py +307 -169
- qolsys_controller/zwave_device.py +108 -95
- qolsys_controller/zwave_dimmer.py +53 -50
- qolsys_controller/zwave_garagedoor.py +0 -1
- qolsys_controller/zwave_generic.py +2 -3
- qolsys_controller/zwave_lock.py +47 -44
- qolsys_controller/zwave_outlet.py +0 -1
- qolsys_controller/zwave_thermostat.py +112 -118
- qolsys_controller-0.0.62.dist-info/METADATA +89 -0
- qolsys_controller-0.0.62.dist-info/RECORD +69 -0
- {qolsys_controller-0.0.38.dist-info → qolsys_controller-0.0.62.dist-info}/WHEEL +1 -1
- qolsys_controller/plugin.py +0 -34
- qolsys_controller/plugin_c4.py +0 -17
- qolsys_controller/plugin_remote.py +0 -1298
- qolsys_controller-0.0.38.dist-info/METADATA +0 -93
- qolsys_controller-0.0.38.dist-info/RECORD +0 -68
- {qolsys_controller-0.0.38.dist-info → qolsys_controller-0.0.62.dist-info}/licenses/LICENSE +0 -0
qolsys_controller/partition.py
CHANGED
|
@@ -11,19 +11,22 @@ LOGGER = logging.getLogger(__name__)
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class QolsysPartition(QolsysObservable):
|
|
14
|
-
|
|
15
14
|
EXIT_SOUNDS_ARRAY = ["ON", "OFF", ""] # noqa: RUF012
|
|
16
15
|
ENTRY_DELAYS_ARRAY = ["ON", "OFF", ""] # noqa: RUF012
|
|
17
16
|
|
|
18
|
-
def __init__(
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
partition_dict: dict[str, str],
|
|
20
|
+
settings_dict: dict[str, str],
|
|
21
|
+
alarm_state: PartitionAlarmState,
|
|
22
|
+
alarm_type_array: list[PartitionAlarmType],
|
|
23
|
+
) -> None:
|
|
21
24
|
super().__init__()
|
|
22
25
|
|
|
23
26
|
# Partition info (partition table)
|
|
24
|
-
self._id: str = partition_dict.get("partition_id")
|
|
25
|
-
self._name: str = partition_dict.get("name")
|
|
26
|
-
self._devices = partition_dict.get("devices")
|
|
27
|
+
self._id: str = partition_dict.get("partition_id", "")
|
|
28
|
+
self._name: str = partition_dict.get("name", "")
|
|
29
|
+
self._devices = partition_dict.get("devices", "")
|
|
27
30
|
|
|
28
31
|
# Partition Settings (qolsyssettings table)
|
|
29
32
|
self._system_status: PartitionSystemStatus = PartitionSystemStatus(settings_dict.get("SYSTEM_STATUS", ""))
|
|
@@ -38,58 +41,90 @@ class QolsysPartition(QolsysObservable):
|
|
|
38
41
|
self._alarm_type_array: list[PartitionAlarmType] = alarm_type_array
|
|
39
42
|
|
|
40
43
|
# Other
|
|
41
|
-
self._command_exit_sounds = True
|
|
42
|
-
self._command_arm_stay_instant = True
|
|
43
|
-
self._command_arm_stay_silent_disarming = False
|
|
44
|
-
self._command_arm_entry_delay = True
|
|
44
|
+
self._command_exit_sounds: bool = True
|
|
45
|
+
self._command_arm_stay_instant: bool = True
|
|
46
|
+
self._command_arm_stay_silent_disarming: bool = False
|
|
47
|
+
self._command_arm_entry_delay: bool = True
|
|
45
48
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
def update_partition(self, data: dict[str, str]) -> None:
|
|
50
|
+
# Check if we are updating same partition_id
|
|
51
|
+
partition_id_update = data.get("partition_id", "")
|
|
52
|
+
if partition_id_update != self.id:
|
|
53
|
+
LOGGER.error(
|
|
54
|
+
"Updating Partition%s (%s) with Partition '%s' (different id)", self._id, self._name, partition_id_update
|
|
55
|
+
)
|
|
56
|
+
return
|
|
49
57
|
|
|
50
|
-
|
|
51
|
-
def name(self) -> str:
|
|
52
|
-
return self._name
|
|
58
|
+
self.start_batch_update()
|
|
53
59
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
60
|
+
# Update Partition Name
|
|
61
|
+
if "name" in data:
|
|
62
|
+
self.name = data.get("name", "")
|
|
57
63
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
64
|
+
# Update Partition Devices
|
|
65
|
+
if "devices" in data:
|
|
66
|
+
self._devices = data.get("devices", "")
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
def alarm_state(self) -> PartitionAlarmState:
|
|
64
|
-
return self._alarm_state
|
|
68
|
+
self.end_batch_update()
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return self._alarm_type_array
|
|
70
|
+
def update_settings(self, data: dict[str, str]) -> None:
|
|
71
|
+
self.start_batch_update()
|
|
69
72
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
+
# Update system_status
|
|
74
|
+
if "SYSTEM_STATUS" in data:
|
|
75
|
+
self.system_status = PartitionSystemStatus[data.get("SYSTEM_STATUS", "")]
|
|
73
76
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
+
# Update system_status_changed_time
|
|
78
|
+
if "SYSTEM_STATUS_CHANGED_TIME" in data:
|
|
79
|
+
self.system_status_changed_time = data.get("SYSTEM_STATUS_CHANGED_TIME", "")
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
+
# Update exit_sounds
|
|
82
|
+
if "EXIT_SOUNDS" in data:
|
|
83
|
+
self.exit_sounds = data.get("EXIT_SOUNDS", "")
|
|
84
|
+
|
|
85
|
+
# Update entry_delays
|
|
86
|
+
if "ENTRY_DELAYS" in data:
|
|
87
|
+
self.entry_delays = data.get("ENTRY_DELAYS", "")
|
|
88
|
+
|
|
89
|
+
self.end_batch_update()
|
|
90
|
+
|
|
91
|
+
def to_dict_partition(self) -> dict[str, str]:
|
|
92
|
+
return {
|
|
93
|
+
"partition_id": self.id,
|
|
94
|
+
"name": self.name,
|
|
95
|
+
"devices": self._devices,
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
def to_dict_settings(self) -> dict[str, str]:
|
|
99
|
+
return {
|
|
100
|
+
"SYSTEM_STATUS": self.system_status.value,
|
|
101
|
+
"SYSTEM_STATUS_CHANGED_TIME": self.system_status_changed_time,
|
|
102
|
+
"EXIT_SOUNDS": self.exit_sounds,
|
|
103
|
+
"ENTRY_DELAYS": self.entry_delays,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
# -----------------------------
|
|
107
|
+
# properties + setters
|
|
108
|
+
# -----------------------------
|
|
81
109
|
|
|
82
110
|
@property
|
|
83
|
-
def
|
|
84
|
-
return self.
|
|
111
|
+
def id(self) -> str:
|
|
112
|
+
return self._id
|
|
85
113
|
|
|
86
114
|
@property
|
|
87
|
-
def
|
|
88
|
-
return self.
|
|
115
|
+
def name(self) -> str:
|
|
116
|
+
return self._name
|
|
117
|
+
|
|
118
|
+
@name.setter
|
|
119
|
+
def name(self, value: str) -> None:
|
|
120
|
+
if self._name != value:
|
|
121
|
+
LOGGER.debug("Partition%s (%s) - name: %s", self._id, self._name, value)
|
|
122
|
+
self._name = value
|
|
123
|
+
self.notify()
|
|
89
124
|
|
|
90
125
|
@property
|
|
91
|
-
def
|
|
92
|
-
return self.
|
|
126
|
+
def system_status(self) -> PartitionSystemStatus:
|
|
127
|
+
return self._system_status
|
|
93
128
|
|
|
94
129
|
@system_status.setter
|
|
95
130
|
def system_status(self, new_value: PartitionSystemStatus) -> None:
|
|
@@ -98,6 +133,10 @@ class QolsysPartition(QolsysObservable):
|
|
|
98
133
|
self._system_status = new_value
|
|
99
134
|
self.notify()
|
|
100
135
|
|
|
136
|
+
@property
|
|
137
|
+
def system_status_changed_time(self) -> str:
|
|
138
|
+
return self._system_status_changed_time
|
|
139
|
+
|
|
101
140
|
@system_status_changed_time.setter
|
|
102
141
|
def system_status_changed_time(self, value: str) -> None:
|
|
103
142
|
if self._system_status_changed_time != value:
|
|
@@ -105,6 +144,10 @@ class QolsysPartition(QolsysObservable):
|
|
|
105
144
|
self._system_status_changed_time = value
|
|
106
145
|
self.notify()
|
|
107
146
|
|
|
147
|
+
@property
|
|
148
|
+
def alarm_state(self) -> PartitionAlarmState:
|
|
149
|
+
return self._alarm_state
|
|
150
|
+
|
|
108
151
|
@alarm_state.setter
|
|
109
152
|
def alarm_state(self, new_value: PartitionAlarmState) -> None:
|
|
110
153
|
if self._alarm_state != new_value:
|
|
@@ -112,9 +155,12 @@ class QolsysPartition(QolsysObservable):
|
|
|
112
155
|
self._alarm_state = new_value
|
|
113
156
|
self.notify()
|
|
114
157
|
|
|
158
|
+
@property
|
|
159
|
+
def alarm_type_array(self) -> list[PartitionAlarmType]:
|
|
160
|
+
return self._alarm_type_array
|
|
161
|
+
|
|
115
162
|
@alarm_type_array.setter
|
|
116
163
|
def alarm_type_array(self, new_alarm_type_array: list[PartitionAlarmType]) -> None:
|
|
117
|
-
|
|
118
164
|
# If no changes are detected: return without notification
|
|
119
165
|
if sorted(new_alarm_type_array, key=lambda c: c.value) == sorted(self.alarm_type_array, key=lambda c: c.value):
|
|
120
166
|
return
|
|
@@ -130,30 +176,9 @@ class QolsysPartition(QolsysObservable):
|
|
|
130
176
|
|
|
131
177
|
self.append_alarm_type(new_alarm_type_array)
|
|
132
178
|
|
|
133
|
-
@
|
|
134
|
-
def
|
|
135
|
-
|
|
136
|
-
LOGGER.debug("Partition%s (%s) - name: %s", self._id, self._name, value)
|
|
137
|
-
self._name = value
|
|
138
|
-
self.notify()
|
|
139
|
-
|
|
140
|
-
def append_alarm_type(self, new_alarm_type_array: list[PartitionAlarmType]) -> None:
|
|
141
|
-
|
|
142
|
-
data_changed = False
|
|
143
|
-
|
|
144
|
-
for new_alarm_type in new_alarm_type_array:
|
|
145
|
-
|
|
146
|
-
# Value already in array
|
|
147
|
-
if new_alarm_type in self._alarm_type_array:
|
|
148
|
-
continue
|
|
149
|
-
|
|
150
|
-
self._alarm_type_array.append(new_alarm_type)
|
|
151
|
-
data_changed = True
|
|
152
|
-
|
|
153
|
-
if data_changed:
|
|
154
|
-
self.notify()
|
|
155
|
-
for alarm in self._alarm_type_array:
|
|
156
|
-
LOGGER.debug("Partition%s (%s) - alarm_type: %s", self._id, self._name, alarm)
|
|
179
|
+
@property
|
|
180
|
+
def exit_sounds(self) -> str:
|
|
181
|
+
return self._exit_sounds
|
|
157
182
|
|
|
158
183
|
@exit_sounds.setter
|
|
159
184
|
def exit_sounds(self, value: str) -> None:
|
|
@@ -166,6 +191,10 @@ class QolsysPartition(QolsysObservable):
|
|
|
166
191
|
self._exit_sounds = value
|
|
167
192
|
self.notify()
|
|
168
193
|
|
|
194
|
+
@property
|
|
195
|
+
def entry_delays(self) -> str:
|
|
196
|
+
return self._entry_delays
|
|
197
|
+
|
|
169
198
|
@entry_delays.setter
|
|
170
199
|
def entry_delays(self, value: str) -> None:
|
|
171
200
|
if value not in self.ENTRY_DELAYS_ARRAY:
|
|
@@ -177,85 +206,58 @@ class QolsysPartition(QolsysObservable):
|
|
|
177
206
|
self._entry_delays = value
|
|
178
207
|
self.notify()
|
|
179
208
|
|
|
209
|
+
@property
|
|
210
|
+
def command_exit_sounds(self) -> bool:
|
|
211
|
+
return self._command_exit_sounds
|
|
212
|
+
|
|
180
213
|
@command_exit_sounds.setter
|
|
181
|
-
def command_exit_sounds(self, value:
|
|
214
|
+
def command_exit_sounds(self, value: bool) -> None:
|
|
182
215
|
self._command_exit_sounds = value
|
|
183
216
|
LOGGER.debug("Partition%s (%s) - command_exit_sounds: %s", self._id, self._name, value)
|
|
184
217
|
self.notify()
|
|
185
218
|
|
|
219
|
+
@property
|
|
220
|
+
def command_arm_stay_instant(self) -> bool:
|
|
221
|
+
return self._command_arm_stay_instant
|
|
222
|
+
|
|
186
223
|
@command_arm_stay_instant.setter
|
|
187
|
-
def command_arm_stay_instant(self, value:
|
|
224
|
+
def command_arm_stay_instant(self, value: bool) -> None:
|
|
188
225
|
self._command_arm_stay_instant = value
|
|
189
226
|
LOGGER.debug("Partition%s (%s) - arm_stay_instant: %s", self._id, self._name, value)
|
|
190
227
|
self.notify()
|
|
191
228
|
|
|
229
|
+
@property
|
|
230
|
+
def command_arm_stay_silent_disarming(self) -> bool:
|
|
231
|
+
return self._command_arm_stay_silent_disarming
|
|
232
|
+
|
|
192
233
|
@command_arm_stay_silent_disarming.setter
|
|
193
234
|
def command_arm_stay_silent_disarming(self, value: bool) -> None:
|
|
194
235
|
self._command_arm_stay_silent_disarming = value
|
|
195
236
|
LOGGER.debug("Partition%s (%s) - arm_stay_silent_disarming: %s", self._id, self._name, value)
|
|
196
237
|
self.notify()
|
|
197
238
|
|
|
239
|
+
@property
|
|
240
|
+
def command_arm_entry_delay(self) -> bool:
|
|
241
|
+
return self._command_arm_entry_delay
|
|
242
|
+
|
|
198
243
|
@command_arm_entry_delay.setter
|
|
199
|
-
def command_arm_entry_delay(self, value:bool) -> None:
|
|
244
|
+
def command_arm_entry_delay(self, value: bool) -> None:
|
|
200
245
|
self._command_arm_entry_delay = value
|
|
201
246
|
LOGGER.debug("Partition%s (%s) - command_arm_entry_delay: %s", self._id, self._name, value)
|
|
202
247
|
self.notify()
|
|
203
248
|
|
|
249
|
+
def append_alarm_type(self, new_alarm_type_array: list[PartitionAlarmType]) -> None:
|
|
250
|
+
data_changed = False
|
|
204
251
|
|
|
252
|
+
for new_alarm_type in new_alarm_type_array:
|
|
253
|
+
# Value already in array
|
|
254
|
+
if new_alarm_type in self._alarm_type_array:
|
|
255
|
+
continue
|
|
205
256
|
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
partition_id_update = data.get("partition_id", "")
|
|
209
|
-
if int(partition_id_update) != int(self.id):
|
|
210
|
-
LOGGER.error(
|
|
211
|
-
"Updating Partition%s (%s) with Partition '%s' (different id)", self._id, self._name, partition_id_update)
|
|
212
|
-
return
|
|
213
|
-
|
|
214
|
-
self.start_batch_update()
|
|
215
|
-
|
|
216
|
-
# Update Partition Name
|
|
217
|
-
if "name" in data:
|
|
218
|
-
self.name = data.get("name")
|
|
219
|
-
|
|
220
|
-
# Update Partition Devices
|
|
221
|
-
if "devices" in data:
|
|
222
|
-
self._devices = data.get("devices")
|
|
223
|
-
|
|
224
|
-
self.end_batch_update()
|
|
225
|
-
|
|
226
|
-
def update_settings(self, data: dict) -> None:
|
|
227
|
-
|
|
228
|
-
self.start_batch_update()
|
|
229
|
-
|
|
230
|
-
# Update system_status
|
|
231
|
-
if "SYSTEM_STATUS" in data:
|
|
232
|
-
self.system_status = data.get("SYSTEM_STATUS")
|
|
233
|
-
|
|
234
|
-
# Update system_status_changed_time
|
|
235
|
-
if "SYSTEM_STATUS_CHANGED_TIME" in data:
|
|
236
|
-
self.system_status_changed_time = data.get("SYSTEM_STATUS_CHANGED_TIME")
|
|
237
|
-
|
|
238
|
-
# Update exit_sounds
|
|
239
|
-
if "EXIT_SOUNDS" in data:
|
|
240
|
-
self.exit_sounds = data.get("EXIT_SOUNDS")
|
|
241
|
-
|
|
242
|
-
# Update entry_delays
|
|
243
|
-
if "ENTRY_DELAYS" in data:
|
|
244
|
-
self.entry_delays = data.get("ENTRY_DELAYS")
|
|
245
|
-
|
|
246
|
-
self.end_batch_update()
|
|
247
|
-
|
|
248
|
-
def to_dict_partition(self) -> dict:
|
|
249
|
-
return {
|
|
250
|
-
"partition_id": self.id,
|
|
251
|
-
"name": self.name,
|
|
252
|
-
"devices": self._devices,
|
|
253
|
-
}
|
|
257
|
+
self._alarm_type_array.append(new_alarm_type)
|
|
258
|
+
data_changed = True
|
|
254
259
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
"EXIT_SOUNDS": self.exit_sounds,
|
|
260
|
-
"ENTRY_DELAYS": self.entry_delays,
|
|
261
|
-
}
|
|
260
|
+
if data_changed:
|
|
261
|
+
self.notify()
|
|
262
|
+
for alarm in self._alarm_type_array:
|
|
263
|
+
LOGGER.debug("Partition%s (%s) - alarm_type: %s", self._id, self._name, alarm)
|
qolsys_controller/pki.py
CHANGED
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
import re
|
|
4
|
-
from datetime import datetime, timedelta
|
|
4
|
+
from datetime import datetime, timedelta, timezone
|
|
5
5
|
from pathlib import Path
|
|
6
6
|
|
|
7
7
|
from cryptography import x509
|
|
8
8
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
9
9
|
from cryptography.hazmat.primitives.asymmetric import rsa
|
|
10
|
-
from cryptography.x509 import load_pem_x509_csr
|
|
11
10
|
from cryptography.x509.oid import NameOID
|
|
12
11
|
|
|
13
12
|
from .settings import QolsysSettings
|
|
@@ -18,13 +17,12 @@ LOGGER = logging.getLogger(__name__)
|
|
|
18
17
|
class QolsysPKI:
|
|
19
18
|
def __init__(self, settings: QolsysSettings) -> None:
|
|
20
19
|
self._id = ""
|
|
21
|
-
self._subkeys_directory: Path = Path
|
|
22
|
-
|
|
23
|
-
self.
|
|
24
|
-
self.
|
|
25
|
-
self.
|
|
26
|
-
self.
|
|
27
|
-
self._qolsys = None
|
|
20
|
+
self._subkeys_directory: Path = Path()
|
|
21
|
+
self._key: Path = Path()
|
|
22
|
+
self._cer: Path = Path()
|
|
23
|
+
self._csr: Path = Path()
|
|
24
|
+
self._secure: Path = Path()
|
|
25
|
+
self._qolsys: Path = Path()
|
|
28
26
|
|
|
29
27
|
self._settings = settings
|
|
30
28
|
|
|
@@ -33,7 +31,7 @@ class QolsysPKI:
|
|
|
33
31
|
return self._id
|
|
34
32
|
|
|
35
33
|
def formatted_id(self) -> str:
|
|
36
|
-
return ":".join(self.id[i:i+2] for i in range(0, len(self.id), 2))
|
|
34
|
+
return ":".join(self.id[i : i + 2] for i in range(0, len(self.id), 2))
|
|
37
35
|
|
|
38
36
|
def set_id(self, pki_id: str) -> None:
|
|
39
37
|
self._id = pki_id.replace(":", "").lower()
|
|
@@ -41,23 +39,23 @@ class QolsysPKI:
|
|
|
41
39
|
self._subkeys_directory = self._settings.pki_directory.joinpath(Path(self.id))
|
|
42
40
|
|
|
43
41
|
@property
|
|
44
|
-
def key(self) ->
|
|
42
|
+
def key(self) -> Path:
|
|
45
43
|
return self._key
|
|
46
44
|
|
|
47
45
|
@property
|
|
48
|
-
def cer(self) ->
|
|
46
|
+
def cer(self) -> Path:
|
|
49
47
|
return self._cer
|
|
50
48
|
|
|
51
49
|
@property
|
|
52
|
-
def csr(self) ->
|
|
50
|
+
def csr(self) -> Path:
|
|
53
51
|
return self._csr
|
|
54
52
|
|
|
55
53
|
@property
|
|
56
|
-
def secure(self) ->
|
|
54
|
+
def secure(self) -> Path:
|
|
57
55
|
return self._secure
|
|
58
56
|
|
|
59
57
|
@property
|
|
60
|
-
def qolsys(self) ->
|
|
58
|
+
def qolsys(self) -> Path:
|
|
61
59
|
return self._qolsys
|
|
62
60
|
|
|
63
61
|
def auto_discover_pki(self) -> bool:
|
|
@@ -72,51 +70,6 @@ class QolsysPKI:
|
|
|
72
70
|
|
|
73
71
|
return False
|
|
74
72
|
|
|
75
|
-
def load_private_key(self, key: str) -> bool:
|
|
76
|
-
try:
|
|
77
|
-
self._key = serialization.load_pem_private_key(key.encode(), password=None)
|
|
78
|
-
except ValueError:
|
|
79
|
-
LOGGER.debug("Private Key Value Error")
|
|
80
|
-
return False
|
|
81
|
-
|
|
82
|
-
return True
|
|
83
|
-
|
|
84
|
-
def load_certificate(self, cer: str) -> bool:
|
|
85
|
-
try:
|
|
86
|
-
self._cer = x509.load_pem_x509_certificate(cer.encode(), None)
|
|
87
|
-
except ValueError:
|
|
88
|
-
LOGGER.debug("Certificate Value Error")
|
|
89
|
-
return False
|
|
90
|
-
|
|
91
|
-
return True
|
|
92
|
-
|
|
93
|
-
def load_certificate_signing_request(self, csr: str) -> bool:
|
|
94
|
-
try:
|
|
95
|
-
self._csr = load_pem_x509_csr(csr.encode())
|
|
96
|
-
except ValueError:
|
|
97
|
-
LOGGER.debug("Certificate Signing Request Value Error")
|
|
98
|
-
return False
|
|
99
|
-
|
|
100
|
-
return True
|
|
101
|
-
|
|
102
|
-
def load_qolsys_certificate(self, qolsys: str) -> bool:
|
|
103
|
-
try:
|
|
104
|
-
self._qolsys = x509.load_pem_x509_certificate(qolsys.encode(), None)
|
|
105
|
-
except ValueError:
|
|
106
|
-
LOGGER.debug("Qolsys Certificate Value Error")
|
|
107
|
-
return False
|
|
108
|
-
|
|
109
|
-
return True
|
|
110
|
-
|
|
111
|
-
def load_signed_client_certificate(self, secure: str) -> bool:
|
|
112
|
-
try:
|
|
113
|
-
self._secure = x509.load_pem_x509_certificate(secure.encode(), None)
|
|
114
|
-
except ValueError:
|
|
115
|
-
LOGGER.debug("Client Signed Certificate Value Error")
|
|
116
|
-
return False
|
|
117
|
-
|
|
118
|
-
return True
|
|
119
|
-
|
|
120
73
|
def check_key_file(self) -> bool:
|
|
121
74
|
if self._subkeys_directory.joinpath(self.id + ".key").resolve().exists():
|
|
122
75
|
LOGGER.debug("Found KEY")
|
|
@@ -157,23 +110,22 @@ class QolsysPKI:
|
|
|
157
110
|
return self._subkeys_directory.joinpath(self.id + ".key")
|
|
158
111
|
|
|
159
112
|
@property
|
|
160
|
-
def csr_file_path(self) ->
|
|
113
|
+
def csr_file_path(self) -> Path:
|
|
161
114
|
return self._subkeys_directory.joinpath(self.id + ".csr")
|
|
162
115
|
|
|
163
116
|
@property
|
|
164
|
-
def cer_file_path(self) ->
|
|
117
|
+
def cer_file_path(self) -> Path:
|
|
165
118
|
return self._subkeys_directory.joinpath(self.id + ".cer")
|
|
166
119
|
|
|
167
120
|
@property
|
|
168
|
-
def secure_file_path(self) ->
|
|
121
|
+
def secure_file_path(self) -> Path:
|
|
169
122
|
return self._subkeys_directory.joinpath(self.id + ".secure")
|
|
170
123
|
|
|
171
124
|
@property
|
|
172
|
-
def qolsys_cer_file_path(self) ->
|
|
125
|
+
def qolsys_cer_file_path(self) -> Path:
|
|
173
126
|
return self._subkeys_directory.joinpath(self.id + ".qolsys")
|
|
174
127
|
|
|
175
128
|
def create(self, mac: str, key_size: int) -> bool:
|
|
176
|
-
|
|
177
129
|
self.set_id(mac)
|
|
178
130
|
|
|
179
131
|
# Check if directory exist
|
|
@@ -207,48 +159,68 @@ class QolsysPKI:
|
|
|
207
159
|
self._subkeys_directory.resolve().mkdir(parents=True)
|
|
208
160
|
|
|
209
161
|
LOGGER.debug("Creating KEY")
|
|
210
|
-
private_key = rsa.generate_private_key(public_exponent=65537,
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
162
|
+
private_key = rsa.generate_private_key(public_exponent=65537, key_size=key_size)
|
|
163
|
+
private_pem = private_key.private_bytes(
|
|
164
|
+
encoding=serialization.Encoding.PEM,
|
|
165
|
+
format=serialization.PrivateFormat.PKCS8,
|
|
166
|
+
encryption_algorithm=serialization.NoEncryption(),
|
|
167
|
+
)
|
|
215
168
|
with self._subkeys_directory.joinpath(self.id + ".key").open("wb") as file:
|
|
216
169
|
file.write(private_pem)
|
|
217
170
|
|
|
218
171
|
LOGGER.debug("Creating CER")
|
|
219
|
-
subject = issuer = x509.Name(
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
172
|
+
subject = issuer = x509.Name(
|
|
173
|
+
[
|
|
174
|
+
x509.NameAttribute(NameOID.COUNTRY_NAME, "US"),
|
|
175
|
+
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "SanJose"),
|
|
176
|
+
x509.NameAttribute(NameOID.LOCALITY_NAME, ""),
|
|
177
|
+
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Qolsys Inc."),
|
|
178
|
+
x509.NameAttribute(NameOID.COMMON_NAME, "www.qolsys.com "),
|
|
179
|
+
]
|
|
180
|
+
)
|
|
181
|
+
cert = (
|
|
182
|
+
x509.CertificateBuilder()
|
|
183
|
+
.subject_name(
|
|
184
|
+
subject,
|
|
185
|
+
)
|
|
186
|
+
.issuer_name(
|
|
187
|
+
issuer,
|
|
188
|
+
)
|
|
189
|
+
.public_key(
|
|
190
|
+
private_key.public_key(),
|
|
191
|
+
)
|
|
192
|
+
.serial_number(
|
|
193
|
+
x509.random_serial_number(),
|
|
194
|
+
)
|
|
195
|
+
.not_valid_before(
|
|
196
|
+
datetime.now(timezone.utc), # noqa: UP017
|
|
197
|
+
)
|
|
198
|
+
.not_valid_after(
|
|
199
|
+
datetime.now(timezone.utc) + timedelta(days=3650), # noqa: UP017
|
|
200
|
+
)
|
|
201
|
+
.add_extension(
|
|
202
|
+
x509.BasicConstraints(ca=False, path_length=None),
|
|
203
|
+
critical=True,
|
|
204
|
+
)
|
|
205
|
+
.sign(private_key, hashes.SHA256())
|
|
206
|
+
)
|
|
241
207
|
cert_pem = cert.public_bytes(encoding=serialization.Encoding.PEM)
|
|
242
208
|
|
|
243
209
|
with self._subkeys_directory.joinpath(self.id + ".cer").open("wb") as file:
|
|
244
210
|
file.write(cert_pem)
|
|
245
211
|
|
|
246
212
|
LOGGER.debug("Creating CSR")
|
|
247
|
-
csr =
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
213
|
+
csr = (
|
|
214
|
+
x509.CertificateSigningRequestBuilder()
|
|
215
|
+
.subject_name(
|
|
216
|
+
subject,
|
|
217
|
+
)
|
|
218
|
+
.add_extension(
|
|
219
|
+
x509.BasicConstraints(ca=False, path_length=None),
|
|
220
|
+
critical=True,
|
|
221
|
+
)
|
|
222
|
+
.sign(private_key, hashes.SHA256())
|
|
223
|
+
)
|
|
252
224
|
|
|
253
225
|
# Save CSR to file
|
|
254
226
|
csr_pem = csr.public_bytes(encoding=serialization.Encoding.PEM)
|