summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJannik Schönartz2021-01-29 13:13:41 +0100
committerJannik Schönartz2021-01-29 13:13:41 +0100
commit763c5bd4e68e56b556526f0c06b0d300d12c2e79 (patch)
tree6899f0c5dd94413af1d3d208bc511594972aacdf
parent[server/wol] Add non-capital letters to mac validator (diff)
downloadbas-763c5bd4e68e56b556526f0c06b0d300d12c2e79.tar.gz
bas-763c5bd4e68e56b556526f0c06b0d300d12c2e79.tar.xz
bas-763c5bd4e68e56b556526f0c06b0d300d12c2e79.zip
[server/pci] Add lib for downloading and parsing the current pci id file
-rw-r--r--server/lib/pci/index.js192
1 files changed, 192 insertions, 0 deletions
diff --git a/server/lib/pci/index.js b/server/lib/pci/index.js
new file mode 100644
index 0000000..5a7d468
--- /dev/null
+++ b/server/lib/pci/index.js
@@ -0,0 +1,192 @@
+/* global __appdir */
+var path = require('path')
+const fs = require('fs')
+const crypto = require('crypto')
+const axios = require('axios')
+const pciRepoApi = 'https://api.github.com/repos/pciutils/pciids/contents/'
+const pciRepoDataApi = 'https://api.github.com/repos/pciutils/pciids/git/blobs/'
+const pciIdsFilePath = path.join(__appdir, 'lib', 'pci', 'pci.ids')
+var parsedPciList = {}
+var parsedDeviceClasses = {}
+
+// Non-Api way to the the raw file:
+// const pciIdsUrl = 'https://github.com/pciutils/pciids/raw/master/pci.ids'
+
+module.exports = {
+ parseIds: async function (vendorId, deviceId, subvendorId, subdeviceId, classId, subclassId) {
+ await updatePciIds()
+ if (Object.keys(parsedPciList).length === 0) await parsePciList()
+
+ let pciInformation = {
+ 'vendorId': vendorId,
+ 'vendor': vendorId ? parsedPciList[vendorId].name : undefined,
+ 'deviceId': deviceId,
+ 'device': deviceId ? parsedPciList[vendorId].devices[deviceId].name : undefined,
+ 'subvendorId': subvendorId,
+ 'subvendor': (subvendorId && subdeviceId) ? parsedPciList[vendorId].devices[deviceId].subsystems[subvendorId][subdeviceId].name : undefined,
+ 'classId': classId,
+ 'class': classId ? parsedDeviceClasses[classId].name : undefined,
+ 'subclassId': subclassId,
+ 'subclass': subclassId ? parsedDeviceClasses[classId].subclasses[subclassId].name : undefined
+ }
+
+ return pciInformation
+ }
+}
+
+async function updatePciIds () {
+ // Check if the file in the git is newer than the file created.
+
+ let response = await axios.get(pciRepoApi)
+ response = response.data
+
+ // Get SHA of the pci.ids file
+ const sha = response.filter(x => x.name === 'pci.ids')[0].sha
+
+ if (fs.existsSync(pciIdsFilePath)) {
+ /* Calculate own sha value
+ * Git sha1 value of a file is calculated like this:
+ * 'blob' + ' ' + content.length + '\0' + content
+ */
+ const pciids = fs.readFileSync(pciIdsFilePath)
+ const blobprefix = 'blob' + ' ' + pciids.length + '\0'
+ const sha1sum = crypto.createHash('sha1').update(blobprefix + pciids).digest('hex')
+
+ // Exit if there isn't a new version
+ if (sha === sha1sum) return
+ }
+
+ // Download the new list
+ await downloadPciIds(sha)
+}
+
+async function downloadPciIds (sha) {
+ // Get the newest version from the github api
+ let request = await axios.get(pciRepoDataApi + sha)
+ request = request.data
+
+ // Decode base64 encoding
+ const buffer = Buffer.from(request.content, 'base64')
+ const file = buffer.toString('utf-8')
+
+ // Override the content in the pci.ids file with the new one
+ fs.writeFile(pciIdsFilePath, file, { flag: 'w' }, (err) => {
+ if (err) throw err
+
+ // Reparse the pci file
+ parsePciList()
+ })
+}
+
+/*
+ * Syntax of the pci.ids file:
+ * # vendor vendor_name
+ * # device device_name <-- single tab
+ * # subvendor subdevice subsystem_name <-- two tabs
+ * parsed structure:
+ * {
+ * '<vendor_id>': {
+ * 'name': '<vendor_name>',
+ * 'devices': {
+ * '<device_id>': {
+ * 'name': '<device_name>',
+ * 'subsystems': {
+ * '<subvendor_id>': {
+ * '<subdevice_id>': {
+ * 'name': '<subsystem_name>'
+ * }
+ * }
+ * }
+ * }
+ * }
+ * }
+ * }
+ *
+ * # C class class_name
+ * # subclass subclass_name <-- single tab
+ * # prog-if prog-if_name <-- two tabs
+ * parsed structure:
+ * {
+ * '<class_id>': {
+ * 'name': '<class_name>',
+ * 'subclasses': {
+ * '<subclass_id>': {
+ * 'name': '<subclass_name>',
+ * 'interfaces': {
+ * '<interface_id>': {
+ * 'name': '<interface_name>'
+ * }
+ * }
+ * }
+ * }
+ * }
+ * }
+ */
+function parsePciList () {
+ let result = {}
+ let deviceClasses = {}
+
+ // Read file
+ const lines = fs.readFileSync(pciIdsFilePath).toString().split('\n')
+ const regexVendor = /^[0-9A-Fa-f]{4}/
+ const regexDevice = /^\t[0-9A-Fa-f]{4}/
+ const regexSubVD = /^\t\t[0-9A-Fa-f]{4}/
+
+ const regexClass = /^C [0-9A-Fa-f]{2}/
+ const regexSubclass = /^\t[0-9A-Fa-f]{2}/
+ const regexProgIf = /^\t\t[0-9A-Fa-f]{2}/
+
+ let lastVendorId = ''
+ let lastDeviceId = ''
+ let lastClassId = ''
+ let lastSubClassId = ''
+
+ for (let line of lines) {
+ if (line.startsWith('#')) continue
+ else if (line === '') continue
+ else if (line.match(regexVendor)) {
+ const vendor = line.substring(0, 4)
+ const name = line.substring(6)
+ result[vendor] = {
+ 'name': name,
+ 'devices': {}
+ }
+ lastVendorId = vendor
+ } else if (line.match(regexDevice)) {
+ const device = line.substring(1, 5)
+ const name = line.substring(7)
+ result[lastVendorId].devices[device] = {
+ 'name': name,
+ 'subsystems': {}
+ }
+ lastDeviceId = device
+ } else if (line.match(regexSubVD)) {
+ const subvendor = line.substring(2, 6)
+ const subdevice = line.substring(7, 11)
+ const subsystem = line.substring(13)
+
+ if (result[lastVendorId].devices[lastDeviceId].subsystems[subvendor] === undefined) result[lastVendorId].devices[lastDeviceId][subvendor] = {}
+ result[lastVendorId].devices[lastDeviceId][subvendor][subdevice] = {
+ 'name': subsystem
+ }
+ } else if (line.match(regexClass)) {
+ deviceClasses[line.substring(2, 4)] = {
+ 'name': line.substring(6),
+ 'subclasses': {}
+ }
+ lastClassId = line.substring(2, 4)
+ } else if (line.match(regexSubclass)) {
+ deviceClasses[lastClassId].subclasses[line.substring(1, 3)] = {
+ 'name': line.substring(5),
+ 'interfaces': {}
+ }
+ lastSubClassId = line.substring(1, 3)
+ } else if (line.match(regexProgIf)) {
+ deviceClasses[lastClassId].subclasses[lastSubClassId].interfaces[line.substring(2, 4)] = {
+ 'name': line.substring(6)
+ }
+ }
+ }
+ parsedPciList = result
+ parsedDeviceClasses = deviceClasses
+}