add inxi in parsing and show in details of devs

This commit is contained in:
Cayo Puigdefabregas 2024-11-15 12:47:08 +01:00
parent b7d7b9041d
commit a0276f439e
6 changed files with 340 additions and 417 deletions

View File

@ -69,7 +69,11 @@
{{ dev.manufacturer }} {{ dev.manufacturer }}
</td> </td>
<td> <td>
{% if dev.version %}
{{dev.version}} {{ dev.model }}
{% else %}
{{ dev.model }} {{ dev.model }}
{% endif %}
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -300,6 +300,12 @@ class Device:
self.get_last_evidence() self.get_last_evidence()
return self.last_evidence.get_model() return self.last_evidence.get_model()
@property
def version(self):
if not self.last_evidence:
self.get_last_evidence()
return self.last_evidence.get_version()
@property @property
def components(self): def components(self):
if not self.last_evidence: if not self.last_evidence:

View File

@ -53,34 +53,41 @@
</div> </div>
{% endif %} {% endif %}
<div class="row mb-3"> <div class="row mb-1">
<div class="col-lg-3 col-md-4 label">Type</div> <div class="col-lg-3 col-md-4 label">Type</div>
<div class="col-lg-9 col-md-8">{{ object.type }}</div> <div class="col-lg-9 col-md-8">{{ object.type }}</div>
</div> </div>
{% if object.is_websnapshot and object.last_user_evidence %} {% if object.is_websnapshot and object.last_user_evidence %}
{% for k, v in object.last_user_evidence %} {% for k, v in object.last_user_evidence %}
<div class="row mb-3"> <div class="row mb-1">
<div class="col-lg-3 col-md-4 label">{{ k }}</div> <div class="col-lg-3 col-md-4 label">{{ k }}</div>
<div class="col-lg-9 col-md-8">{{ v|default:'' }}</div> <div class="col-lg-9 col-md-8">{{ v|default:'' }}</div>
</div> </div>
{% endfor %} {% endfor %}
{% else %} {% else %}
<div class="row mb-3"> <div class="row mb-1">
<div class="col-lg-3 col-md-4 label"> <div class="col-lg-3 col-md-4 label">
{% trans 'Manufacturer' %} {% trans 'Manufacturer' %}
</div> </div>
<div class="col-lg-9 col-md-8">{{ object.manufacturer|default:'' }}</div> <div class="col-lg-9 col-md-8">{{ object.manufacturer|default:'' }}</div>
</div> </div>
<div class="row mb-3"> <div class="row mb-1">
<div class="col-lg-3 col-md-4 label"> <div class="col-lg-3 col-md-4 label">
{% trans 'Model' %} {% trans 'Model' %}
</div> </div>
<div class="col-lg-9 col-md-8">{{ object.model|default:'' }}</div> <div class="col-lg-9 col-md-8">{{ object.model|default:'' }}</div>
</div> </div>
<div class="row mb-3"> <div class="row mb-1">
<div class="col-lg-3 col-md-4 label">
{% trans 'Version' %}
</div>
<div class="col-lg-9 col-md-8">{{ object.version|default:'' }}</div>
</div>
<div class="row mb-1">
<div class="col-lg-3 col-md-4 label"> <div class="col-lg-3 col-md-4 label">
{% trans 'Serial Number' %} {% trans 'Serial Number' %}
</div> </div>

View File

@ -5,7 +5,7 @@ from django.db import models
from utils.constants import STR_EXTEND_SIZE, CHASSIS_DH from utils.constants import STR_EXTEND_SIZE, CHASSIS_DH
from evidence.xapian import search from evidence.xapian import search
from evidence.parse_details import ParseSnapshot from evidence.parse_details import ParseSnapshot, get_inxi, get_inxi_key
from user.models import User, Institution from user.models import User, Institution
@ -39,6 +39,7 @@ class Evidence:
self.doc = None self.doc = None
self.created = None self.created = None
self.dmi = None self.dmi = None
self.inxi = None
self.annotations = [] self.annotations = []
self.components = [] self.components = []
self.default = "n/a" self.default = "n/a"
@ -72,7 +73,22 @@ class Evidence:
if not self.is_legacy(): if not self.is_legacy():
dmidecode_raw = self.doc["data"]["dmidecode"] dmidecode_raw = self.doc["data"]["dmidecode"]
inxi_raw = self.doc["data"]["inxi"]
self.dmi = DMIParse(dmidecode_raw) self.dmi = DMIParse(dmidecode_raw)
try:
self.inxi = json.loads(inxi_raw)
machine = get_inxi_key(self.inxi, 'Machine')
for m in machine:
system = get_inxi(m, "System")
if system:
self.device_manufacturer = system
self.device_model = get_inxi(m, "product")
self.device_serial_number = get_inxi(m, "serial")
self.device_chassis = get_inxi(m, "Type")
self.device_version = get_inxi(m, "v")
except Exception:
return
def get_time(self): def get_time(self):
if not self.doc: if not self.doc:
@ -98,6 +114,9 @@ class Evidence:
if self.is_legacy(): if self.is_legacy():
return self.doc['device']['manufacturer'] return self.doc['device']['manufacturer']
if self.inxi:
return self.device_manufacturer
return self.dmi.manufacturer().strip() return self.dmi.manufacturer().strip()
def get_model(self): def get_model(self):
@ -110,11 +129,17 @@ class Evidence:
if self.is_legacy(): if self.is_legacy():
return self.doc['device']['model'] return self.doc['device']['model']
if self.inxi:
return self.device_model
return self.dmi.model().strip() return self.dmi.model().strip()
def get_chassis(self): def get_chassis(self):
if self.is_legacy(): if self.is_legacy():
return self.doc['device']['model'] return self.doc['device']['model']
if self.inxi:
return self.device_chassis
chassis = self.dmi.get("Chassis")[0].get("Type", '_virtual') chassis = self.dmi.get("Chassis")[0].get("Type", '_virtual')
lower_type = chassis.lower() lower_type = chassis.lower()
@ -127,8 +152,19 @@ class Evidence:
def get_serial_number(self): def get_serial_number(self):
if self.is_legacy(): if self.is_legacy():
return self.doc['device']['serialNumber'] return self.doc['device']['serialNumber']
if self.inxi:
return self.device_serial_number
return self.dmi.serial_number().strip() return self.dmi.serial_number().strip()
def get_version(self):
if self.inxi:
return self.device_version
return ""
@classmethod @classmethod
def get_all(cls, user): def get_all(cls, user):
return Annotation.objects.filter( return Annotation.objects.filter(

View File

@ -3,35 +3,22 @@ import hashlib
import logging import logging
from dmidecode import DMIParse from dmidecode import DMIParse
from json_repair import repair_json
from evidence.parse_details import get_lshw_child
from evidence.models import Annotation from evidence.models import Annotation
from evidence.xapian import index from evidence.xapian import index
from utils.constants import CHASSIS_DH from utils.constants import CHASSIS_DH
from evidence.parse_details import get_inxi_key, get_inxi
logger = logging.getLogger('django') logger = logging.getLogger('django')
def get_mac(lshw):
try:
if type(lshw) is dict:
hw = lshw
else:
hw = json.loads(lshw)
except json.decoder.JSONDecodeError:
hw = json.loads(repair_json(lshw))
nets = [] def get_mac(inxi):
get_lshw_child(hw, nets, 'network') nets = get_inxi_key(inxi, "Network")
networks = [(nets[i], nets[i + 1]) for i in range(0, len(nets) - 1, 2)]
nets_sorted = sorted(nets, key=lambda x: x['businfo'])
if nets_sorted:
mac = nets_sorted[0]['serial']
logger.debug("The snapshot has the following MAC: %s" , mac)
return mac
for n, iface in networks:
if get_inxi(n, "port"):
return get_inxi(iface, 'mac')
class Build: class Build:
@ -94,38 +81,28 @@ class Build:
value=v value=v
) )
def get_chassis_dh(self):
chassis = self.get_chassis()
lower_type = chassis.lower()
for k, v in CHASSIS_DH.items():
if lower_type in v:
return k
return self.default
def get_sku(self):
return self.dmi.get("System")[0].get("SKU Number", "n/a").strip()
def get_chassis(self):
return self.dmi.get("Chassis")[0].get("Type", '_virtual')
def get_hid(self, snapshot): def get_hid(self, snapshot):
dmidecode_raw = snapshot["data"]["dmidecode"] try:
self.dmi = DMIParse(dmidecode_raw) self.inxi = json.loads(self.json["inxi"])
except Exception:
logger.error("No inxi in snapshot %s", self.uuid)
return ""
machine = get_inxi_key(self.inxi, 'Machine')
for m in machine:
system = get_inxi(m, "System")
if system:
manufacturer = system
model = get_inxi(m, "product")
serial_number = get_inxi(m, "serial")
chassis = get_inxi(m, "Type")
else:
sku = get_inxi(m, "part-nu")
manufacturer = self.dmi.manufacturer().strip() mac = get_mac(self.inxi) or ""
model = self.dmi.model().strip()
chassis = self.get_chassis_dh()
serial_number = self.dmi.serial_number()
sku = self.get_sku()
if not snapshot["data"].get('lshw'):
return f"{manufacturer}{model}{chassis}{serial_number}{sku}"
lshw = snapshot["data"]["lshw"]
# mac = get_mac2(hwinfo_raw) or ""
mac = get_mac(lshw) or ""
if not mac: if not mac:
txt = "Could not retrieve MAC address in snapshot %s" txt = "Could not retrieve MAC address in snapshot %s"
logger.warning(txt, snapshot['uuid']) logger.warning(txt, snapshot['uuid'])
return f"{manufacturer}{model}{chassis}{serial_number}{sku}"
return f"{manufacturer}{model}{chassis}{serial_number}{sku}{mac}" return f"{manufacturer}{model}{chassis}{serial_number}{sku}{mac}"

View File

@ -1,10 +1,10 @@
import re
import json import json
import logging import logging
import numpy as np import numpy as np
from datetime import datetime from datetime import datetime
from dmidecode import DMIParse from dmidecode import DMIParse
from json_repair import repair_json
from utils.constants import CHASSIS_DH, DATASTORAGEINTERFACE from utils.constants import CHASSIS_DH, DATASTORAGEINTERFACE
@ -12,11 +12,19 @@ from utils.constants import CHASSIS_DH, DATASTORAGEINTERFACE
logger = logging.getLogger('django') logger = logging.getLogger('django')
def get_lshw_child(child, nets, component): def get_inxi_key(inxi, component):
if child.get('id') == component: for n in inxi:
nets.append(child) for k, v in n.items():
if child.get('children'): if component in k:
[get_lshw_child(x, nets, component) for x in child['children']] return v
def get_inxi(n, name):
for k, v in n.items():
if f"#{name}" in k:
return v
return ""
class ParseSnapshot: class ParseSnapshot:
@ -24,20 +32,15 @@ class ParseSnapshot:
self.default = default self.default = default
self.dmidecode_raw = snapshot["data"].get("dmidecode", "{}") self.dmidecode_raw = snapshot["data"].get("dmidecode", "{}")
self.smart_raw = snapshot["data"].get("disks", []) self.smart_raw = snapshot["data"].get("disks", [])
self.hwinfo_raw = snapshot["data"].get("hwinfo", "") self.inxi_raw = snapshot["data"].get("inxi", "") or ""
self.lshw_raw = snapshot["data"].get("lshw", {}) or {}
self.lscpi_raw = snapshot["data"].get("lspci", "")
self.device = {"actions": []} self.device = {"actions": []}
self.components = [] self.components = []
self.monitors = []
self.dmi = DMIParse(self.dmidecode_raw) self.dmi = DMIParse(self.dmidecode_raw)
self.smart = self.loads(self.smart_raw) self.smart = self.loads(self.smart_raw)
self.lshw = self.loads(self.lshw_raw) self.inxi = self.loads(self.inxi_raw)
self.hwinfo = self.parse_hwinfo()
self.set_computer() self.set_computer()
self.get_hwinfo_monitors()
self.set_components() self.set_components()
self.snapshot_json = { self.snapshot_json = {
"type": "Snapshot", "type": "Snapshot",
@ -51,283 +54,294 @@ class ParseSnapshot:
} }
def set_computer(self): def set_computer(self):
self.device['manufacturer'] = self.dmi.manufacturer().strip() machine = get_inxi_key(self.inxi, 'Machine')
self.device['model'] = self.dmi.model().strip() for m in machine:
self.device['serialNumber'] = self.dmi.serial_number() system = get_inxi(m, "System")
self.device['type'] = self.get_type() if system:
self.device['sku'] = self.get_sku() self.device['manufacturer'] = system
self.device['version'] = self.get_version() self.device['model'] = get_inxi(m, "product")
self.device['system_uuid'] = self.get_uuid() self.device['serialNumber'] = get_inxi(m, "serial")
self.device['family'] = self.get_family() self.device['type'] = get_inxi(m, "Type")
self.device['chassis'] = self.get_chassis_dh() self.device['chassis'] = self.device['type']
self.device['version'] = get_inxi(m, "v")
else:
self.device['system_uuid'] = get_inxi(m, "uuid")
self.device['sku'] = get_inxi(m, "part-nu")
def set_components(self): def set_components(self):
self.get_mother_board()
self.get_cpu() self.get_cpu()
self.get_ram() self.get_ram()
self.get_mother_board()
self.get_graphic() self.get_graphic()
self.get_data_storage()
self.get_display() self.get_display()
self.get_sound_card()
self.get_networks() self.get_networks()
self.get_sound_card()
def get_cpu(self): self.get_data_storage()
for cpu in self.dmi.get('Processor'): self.get_battery()
serial = cpu.get('Serial Number')
if serial == 'Not Specified' or not serial:
serial = cpu.get('ID').replace(' ', '')
self.components.append(
{
"actions": [],
"type": "Processor",
"speed": self.get_cpu_speed(cpu),
"cores": int(cpu.get('Core Count', 1)),
"model": cpu.get('Version'),
"threads": int(cpu.get('Thread Count', 1)),
"manufacturer": cpu.get('Manufacturer'),
"serialNumber": serial,
"brand": cpu.get('Family'),
"address": self.get_cpu_address(cpu),
"bogomips": self.get_bogomips(),
}
)
def get_ram(self):
for ram in self.dmi.get("Memory Device"):
if ram.get('size') == 'No Module Installed':
continue
if not ram.get("Speed"):
continue
self.components.append(
{
"actions": [],
"type": "RamModule",
"size": self.get_ram_size(ram),
"speed": self.get_ram_speed(ram),
"manufacturer": ram.get("Manufacturer", self.default),
"serialNumber": ram.get("Serial Number", self.default),
"interface": ram.get("Type", "DDR"),
"format": ram.get("Form Factor", "DIMM"),
"model": ram.get("Part Number", self.default),
}
)
def get_mother_board(self): def get_mother_board(self):
for moder_board in self.dmi.get("Baseboard"): machine = get_inxi_key(self.inxi, 'Machine')
self.components.append( mb = {"type": "Motherboard",}
{ for m in machine:
"actions": [], bios_date = get_inxi(m, "date")
"type": "Motherboard", if not bios_date:
"version": moder_board.get("Version"), continue
"serialNumber": moder_board.get("Serial Number", "").strip(), mb["manufacturer"] = get_inxi(m, "Mobo")
"manufacturer": moder_board.get("Manufacturer", "").strip(), mb["model"] = get_inxi(m, "model")
"biosDate": self.get_bios_date(), mb["serialNumber"] = get_inxi(m, "serial")
"ramMaxSize": self.get_max_ram_size(), mb["version"] = get_inxi(m, "v")
"ramSlots": len(self.dmi.get("Memory Device")), mb["biosDate"] = bios_date
"slots": self.get_ram_slots(), mb["biosVersion"] = self.get_bios_version()
"model": moder_board.get("Product Name", "").strip(), mb["firewire"]: self.get_firmware_num()
"firewire": self.get_firmware_num(), mb["pcmcia"]: self.get_pcmcia_num()
"pcmcia": self.get_pcmcia_num(), mb["serial"]: self.get_serial_num()
"serial": self.get_serial_num(), mb["usb"]: self.get_usb_num()
"usb": self.get_usb_num(),
} self.get_ram_slots(mb)
)
self.components.append(mb)
def get_ram_slots(self, mb):
memory = get_inxi_key(self.inxi, 'Memory')
for m in memory:
slots = get_inxi(m, "slots")
if not slots:
continue
mb["slots"] = slots
mb["ramSlots"] = get_inxi(m, "modules")
mb["ramMaxSize"] = get_inxi(m, "capacity")
def get_cpu(self):
cpu = get_inxi_key(self.inxi, 'CPU')
cp = {"type": "Processor"}
vulnerabilities = []
for c in cpu:
base = get_inxi(c, "model")
if base:
cp["model"] = get_inxi(c, "model")
cp["arch"] = get_inxi(c, "arch")
cp["bits"] = get_inxi(c, "bits")
cp["gen"] = get_inxi(c, "gen")
cp["family"] = get_inxi(c, "family")
cp["date"] = get_inxi(c, "built")
continue
des = get_inxi(c, "L1")
if des:
cp["L1"] = des
cp["L2"] = get_inxi(c, "L2")
cp["L3"] = get_inxi(c, "L3")
cp["cpus"] = get_inxi(c, "cpus")
cp["cores"] = get_inxi(c, "cores")
cp["threads"] = get_inxi(c, "threads")
continue
bogo = get_inxi(c, "bogomips")
if bogo:
cp["bogomips"] = bogo
cp["base/boost"] = get_inxi(c, "base/boost")
cp["min/max"] = get_inxi(c, "min/max")
cp["ext-clock"] = get_inxi(c, "ext-clock")
cp["volts"] = get_inxi(c, "volts")
continue
ctype = get_inxi(c, "Type")
if ctype:
v = {"Type": ctype}
status = get_inxi(c, "status")
if status:
v["status"] = status
mitigation = get_inxi(c, "mitigation")
if mitigation:
v["mitigation"] = mitigation
vulnerabilities.append(v)
self.components.append(cp)
def get_ram(self):
memory = get_inxi_key(self.inxi, 'Memory')
mem = {"type": "RamModule"}
for m in memory:
base = get_inxi(m, "System RAM")
if base:
mem["size"] = get_inxi(m, "total")
slot = get_inxi(m, "manufacturer")
if slot:
mem["manufacturer"] = slot
mem["model"] = get_inxi(m, "part-no")
mem["serialNumber"] = get_inxi(m, "serial")
mem["speed"] = get_inxi(m, "speed")
mem["bits"] = get_inxi(m, "data")
mem["interface"] = get_inxi(m, "type")
module = get_inxi(m, "modules")
if module:
mem["modules"] = module
self.components.append(mem)
def get_graphic(self): def get_graphic(self):
displays = [] graphics = get_inxi_key(self.inxi, 'Graphics')
get_lshw_child(self.lshw, displays, 'display')
for c in graphics:
for c in displays: if not get_inxi(c, "Device") or not get_inxi(c, "vendor"):
if not c['configuration'].get('driver', None):
continue continue
self.components.append( self.components.append(
{ {
"actions": [],
"type": "GraphicCard", "type": "GraphicCard",
"memory": self.get_memory_video(c), "memory": self.get_memory_video(c),
"manufacturer": c.get("vendor", self.default), "manufacturer": get_inxi(c, "vendor"),
"model": c.get("product", self.default), "model": get_inxi(c, "Device"),
"serialNumber": c.get("serial", self.default), "arch": get_inxi(c, "arch"),
"serialNumber": get_inxi(c, "serial"),
"integrated": True if get_inxi(c, "port") else False
}
)
def get_battery(self):
bats = get_inxi_key(self.inxi, 'Battery')
for b in bats:
self.components.append(
{
"type": "Battery",
"model": get_inxi(b, "model"),
"serialNumber": get_inxi(b, "serial"),
"condition": get_inxi(b, "condition"),
"cycles": get_inxi(b, "cycles"),
"volts": get_inxi(b, "volts")
} }
) )
def get_memory_video(self, c): def get_memory_video(self, c):
# get info of lspci memory = get_inxi_key(self.inxi, 'Memory')
# pci_id = c['businfo'].split('@')[1]
# lspci.get(pci_id) | grep size for m in memory:
# lspci -v -s 00:02.0 igpu = get_inxi(m, "igpu")
return None agpu = get_inxi(m, "agpu")
ngpu = get_inxi(m, "ngpu")
gpu = get_inxi(m, "gpu")
if igpu or agpu or gpu or ngpu:
return igpu or agpu or gpu or ngpu
return self.default
def get_data_storage(self): def get_data_storage(self):
for sm in self.smart: hdds= get_inxi_key(self.inxi, 'Drives')
if sm.get('smartctl', {}).get('exit_status') == 1: for d in hdds:
usb = get_inxi(d, "type")
if usb == "USB":
continue continue
model = sm.get('model_name')
manufacturer = None
hours = sm.get("power_on_time", {}).get("hours", 0)
if model and len(model.split(" ")) > 1:
mm = model.split(" ")
model = mm[-1]
manufacturer = " ".join(mm[:-1])
self.components.append( serial = get_inxi(d, "serial")
{ if serial:
"actions": self.sanitize(sm), hd = {
"type": self.get_data_storage_type(sm), "type": "Storage",
"model": model, "manufacturer": get_inxi(d, "vendor"),
"manufacturer": manufacturer, "model": get_inxi(d, "model"),
"serialNumber": sm.get('serial_number'), "serialNumber": get_inxi(d, "serial"),
"size": self.get_data_storage_size(sm), "size": get_inxi(d, "size"),
"variant": sm.get("firmware_version"), "speed": get_inxi(d, "speed"),
"interface": self.get_data_storage_interface(sm), "interface": get_inxi(d, "tech"),
"hours": hours, "firmware": get_inxi(d, "fw-rev")
} }
) rpm = get_inxi(d, "rpm")
if rpm:
hd["rpm"] = rpm
family = get_inxi(d, "family")
if family:
hd["family"] = family
sata = get_inxi(d, "sata")
if sata:
hd["sata"] = sata
continue
cycles = get_inxi(d, "cycles")
if cycles:
hd['cycles'] = cycles
hd["health"] = get_inxi(d, "health")
hd["time of used"] = get_inxi(d, "on")
hd["read used"] = get_inxi(d, "read-units")
hd["written used"] = get_inxi(d, "written-units")
# import pdb; pdb.set_trace()
self.components.append(hd)
continue
hd = {}
def sanitize(self, action): def sanitize(self, action):
return [] return []
def get_bogomips(self):
if not self.hwinfo:
return self.default
bogomips = 0
for row in self.hwinfo:
for cel in row:
if 'BogoMips' in cel:
try:
bogomips += float(cel.split(":")[-1])
except:
pass
return bogomips
def get_networks(self): def get_networks(self):
networks = [] nets = get_inxi_key(self.inxi, "Network")
get_lshw_child(self.lshw, networks, 'network') networks = [(nets[i], nets[i + 1]) for i in range(0, len(nets) - 1, 2)]
for c in networks: for n, iface in networks:
capacity = c.get('capacity') model = get_inxi(n, "Device")
wireless = bool(c.get('configuration', {}).get('wireless', False)) if not model:
continue
interface = ''
for k in n.keys():
if "port" in k:
interface = "Integrated"
if "pcie" in k:
interface = "PciExpress"
if get_inxi(n, "type") == "USB":
interface = "USB"
self.components.append( self.components.append(
{ {
"actions": [],
"type": "NetworkAdapter", "type": "NetworkAdapter",
"model": c.get('product'), "model": model,
"manufacturer": c.get('vendor'), "manufacturer": get_inxi(n, 'vendor'),
"serialNumber": c.get('serial'), "serialNumber": get_inxi(iface, 'mac'),
"speed": capacity, "speed": get_inxi(n, "speed"),
"variant": c.get('version', 1), "interface": interface,
"wireless": wireless or False,
"integrated": "PCI:0000:00" in c.get("businfo", ""),
} }
) )
def get_sound_card(self): def get_sound_card(self):
multimedias = [] audio = get_inxi_key(self.inxi, "Audio")
get_lshw_child(self.lshw, multimedias, 'multimedia')
for c in audio:
for c in multimedias: model = get_inxi(c, "Device")
if not model:
continue
self.components.append( self.components.append(
{ {
"actions": [],
"type": "SoundCard", "type": "SoundCard",
"model": c.get('product'), "model": model,
"manufacturer": c.get('vendor'), "manufacturer": get_inxi(c, 'vendor'),
"serialNumber": c.get('serial'), "serialNumber": get_inxi(c, 'serial'),
} }
) )
def get_display(self): # noqa: C901 def get_display(self):
TECHS = 'CRT', 'TFT', 'LED', 'PDP', 'LCD', 'OLED', 'AMOLED' graphics = get_inxi_key(self.inxi, "Graphics")
for c in graphics:
for c in self.monitors: if not get_inxi(c, "Monitor"):
resolution_width, resolution_height = (None,) * 2 continue
refresh, serial, model, manufacturer, size = (None,) * 5
year, week, production_date = (None,) * 3
for x in c:
if "Vendor: " in x:
manufacturer = x.split('Vendor: ')[-1].strip()
if "Model: " in x:
model = x.split('Model: ')[-1].strip()
if "Serial ID: " in x:
serial = x.split('Serial ID: ')[-1].strip()
if " Resolution: " in x:
rs = x.split(' Resolution: ')[-1].strip()
if 'x' in rs:
resolution_width, resolution_height = [
int(r) for r in rs.split('x')
]
if "Frequencies: " in x:
try:
refresh = int(float(x.split(',')[-1].strip()[:-3]))
except Exception:
pass
if 'Year of Manufacture' in x:
year = x.split(': ')[1]
if 'Week of Manufacture' in x:
week = x.split(': ')[1]
if "Size: " in x:
size = self.get_size_monitor(x)
technology = next((t for t in TECHS if t in c[0]), None)
if year and week:
d = '{} {} 0'.format(year, week)
production_date = datetime.strptime(d, '%Y %W %w').isoformat()
self.components.append( self.components.append(
{ {
"actions": [],
"type": "Display", "type": "Display",
"model": model, "model": get_inxi(c, "model"),
"manufacturer": manufacturer, "manufacturer": get_inxi(c, "vendor"),
"serialNumber": serial, "serialNumber": get_inxi(c, "serial"),
'size': size, 'size': get_inxi(c, "size"),
'resolutionWidth': resolution_width, 'diagonal': get_inxi(c, "diag"),
'resolutionHeight': resolution_height, 'resolution': get_inxi(c, "res"),
"productionDate": production_date, "date": get_inxi(c, "built"),
'technology': technology, 'ratio': get_inxi(c, "ratio"),
'refreshRate': refresh,
} }
) )
def get_hwinfo_monitors(self):
for c in self.hwinfo:
monitor = None
external = None
for x in c:
if 'Hardware Class: monitor' in x:
monitor = c
if 'Driver Info' in x:
external = c
if monitor and not external:
self.monitors.append(c)
def get_size_monitor(self, x):
i = 1 / 25.4
t = x.split('Size: ')[-1].strip()
tt = t.split('mm')
if not tt:
return 0
sizes = tt[0].strip()
if 'x' not in sizes:
return 0
w, h = [int(x) for x in sizes.split('x')]
return "{:.2f}".format(np.sqrt(w**2 + h**2) * i)
def get_cpu_address(self, cpu):
default = 64
for ch in self.lshw.get('children', []):
for c in ch.get('children', []):
if c['class'] == 'processor':
return c.get('width', default)
return default
def get_usb_num(self): def get_usb_num(self):
return len( return len(
[ [
@ -364,133 +378,13 @@ class ParseSnapshot:
] ]
) )
def get_bios_date(self): def get_bios_version(self):
return self.dmi.get("BIOS")[0].get("Release Date", self.default) return self.dmi.get("BIOS")[0].get("BIOS Revision", '1')
def get_firmware(self):
return self.dmi.get("BIOS")[0].get("Firmware Revision", '1')
def get_max_ram_size(self):
size = 0
for slot in self.dmi.get("Physical Memory Array"):
capacity = slot.get("Maximum Capacity", '0').split(" ")[0]
size += int(capacity)
return size
def get_ram_slots(self):
slots = 0
for x in self.dmi.get("Physical Memory Array"):
slots += int(x.get("Number Of Devices", 0))
return slots
def get_ram_size(self, ram):
memory = ram.get("Size", "0")
return memory
def get_ram_speed(self, ram):
size = ram.get("Speed", "0")
return size
def get_cpu_speed(self, cpu):
speed = cpu.get('Max Speed', "0")
return speed
def get_sku(self):
return self.dmi.get("System")[0].get("SKU Number", self.default).strip()
def get_version(self):
return self.dmi.get("System")[0].get("Version", self.default).strip()
def get_uuid(self):
return self.dmi.get("System")[0].get("UUID", '').strip()
def get_family(self):
return self.dmi.get("System")[0].get("Family", '')
def get_chassis(self):
return self.dmi.get("Chassis")[0].get("Type", '_virtual')
def get_type(self):
chassis_type = self.get_chassis()
return self.translation_to_devicehub(chassis_type)
def translation_to_devicehub(self, original_type):
lower_type = original_type.lower()
CHASSIS_TYPE = {
'Desktop': [
'desktop',
'low-profile',
'tower',
'docking',
'all-in-one',
'pizzabox',
'mini-tower',
'space-saving',
'lunchbox',
'mini',
'stick',
],
'Laptop': [
'portable',
'laptop',
'convertible',
'tablet',
'detachable',
'notebook',
'handheld',
'sub-notebook',
],
'Server': ['server'],
'Computer': ['_virtual'],
}
for k, v in CHASSIS_TYPE.items():
if lower_type in v:
return k
return self.default
def get_chassis_dh(self):
chassis = self.get_chassis()
lower_type = chassis.lower()
for k, v in CHASSIS_DH.items():
if lower_type in v:
return k
return self.default
def get_data_storage_type(self, x):
# TODO @cayop add more SSDS types
SSDS = ["nvme"]
SSD = 'SolidStateDrive'
HDD = 'HardDrive'
type_dev = x.get('device', {}).get('type')
trim = x.get('trim', {}).get("supported") in [True, "true"]
return SSD if type_dev in SSDS or trim else HDD
def get_data_storage_interface(self, x):
interface = x.get('device', {}).get('protocol', 'ATA')
if interface.upper() in DATASTORAGEINTERFACE:
return interface.upper()
txt = "Sid: {}, interface {} is not in DataStorageInterface Enum".format(
self.sid, interface
)
self.errors("{}".format(err))
def get_data_storage_size(self, x):
return x.get('user_capacity', {}).get('bytes')
def parse_hwinfo(self):
hw_blocks = self.hwinfo_raw.split("\n\n")
return [x.split("\n") for x in hw_blocks]
def loads(self, x): def loads(self, x):
if isinstance(x, str): if isinstance(x, str):
try: try:
try: return json.loads(x)
hw = json.loads(x)
except json.decoder.JSONDecodeError:
hw = json.loads(repair_json(x))
return hw
except Exception as ss: except Exception as ss:
logger.warning("%s", ss) logger.warning("%s", ss)
return {} return {}
@ -502,4 +396,3 @@ class ParseSnapshot:
logger.error(txt) logger.error(txt)
self._errors.append("%s", txt) self._errors.append("%s", txt)