diff --git a/awesome/src/tools/network/access_point.lua b/awesome/src/tools/network/access_point.lua new file mode 100644 index 0000000..918f72c --- /dev/null +++ b/awesome/src/tools/network/access_point.lua @@ -0,0 +1,79 @@ +local gtable = require('gears.table') +local gobject = require('gears.object') +local NM = require('lgi').NM + +local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy') + +local instance = nil +if not instance then + instance = setmetatable({}, { + __call = function(_, device_path) + local self = gobject {} + self.object_path = device_path + self.NetworkManagerAccessPoint = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = 'org.freedesktop.NetworkManager', + interface = 'org.freedesktop.NetworkManager.AccessPoint', + path = device_path, + } + if not NM.utils_ssid_to_utf8(self.NetworkManagerAccessPoint.Ssid) then + self.NetworkManagerAccessPoint = nil + self = nil + return nil + end + + self.NetworkManagerAccessPointProperties = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = 'org.freedesktop.NetworkManager', + interface = 'org.freedesktop.DBus.Properties', + path = device_path, + } + + self.NetworkManagerAccessPointProperties:connect_signal(function(_, _, data) + if data.Strength then + self:emit_signal('NetworkManagerAccessPoint::Strength', data.Strength) + elseif data.LastSeen then + self:emit_signal('NetworkManagerAccessPoint::LastSeen', data.LastSeen) + end + end, 'PropertiesChanged') + self:emit_signal('NetworkManagerAccessPoint::Strength', self.NetworkManagerAccessPoint.Strength) + + + setmetatable(self, { + __index = function(s, key) + if key == 'SSID' then + return NM.utils_ssid_to_utf8(s.NetworkManagerAccessPoint.Ssid) + elseif key == 'Frequency' then + return s.NetworkManagerAccessPoint.Frequency + elseif key == 'MaxBitrate' then + return s.NetworkManagerAccessPoint.MaxBitrate + elseif key == 'HwAddress' then + return s.NetworkManagerAccessPoint.HwAddress + elseif key == 'Strength' then + return s.NetworkManagerAccessPoint.Strength + elseif key == 'Security' then + local str = '' + + if s.Flags == 1 and s.WpaFlags == 0 and s.RsnFlags == 0 then + str = str .. ' WEP' + end + if s.WpaFlags ~= 0 then + str = str .. ' WPA1' + end + if not s.RsnFlags ~= 0 then + str = str .. ' WPA2' + end + if s.WpaFlags == 512 or s.RsnFlags == 512 then + str = str .. ' 802.1X' + end + + return (str:gsub('^%s', '')) + end + end, + }) + + return self + end, + }) +end +return instance diff --git a/awesome/src/tools/network/device.lua b/awesome/src/tools/network/device.lua index c2c2262..d21f045 100644 --- a/awesome/src/tools/network/device.lua +++ b/awesome/src/tools/network/device.lua @@ -1,19 +1,19 @@ -local lgi = require('lgi') -local NM = lgi.NM local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy') local gtable = require('gears.table') local gobject = require('gears.object') -local device = gobject {} -local WIRELESS = gobject {} +local access_point = require('src.tools.network.access_point') +local device = {} +device._private = {} +local WIRELESS = {} -device.DeviceType = { +device._private.DeviceType = { ETHERNET = 1, WIFI = 2, } -device.DeviceState = { +device._private.DeviceState = { UNKNOWN = 0, UNMANAGED = 10, UNAVAILABLE = 20, @@ -29,17 +29,32 @@ device.DeviceState = { FAILED = 120, } +function WIRELESS:IsApActive(ap) + return self.NetworkManagerDeviceWireless.ActiveAccessPoint == ap.object_path +end + function WIRELESS:GetAllAccessPoints() return self.NetworkManagerDeviceWireless:GetAllAccessPoints() end -function WIRELESS:RequestScan() - --TODO: Are options needed? What do they do? - self.NetworkManagerDeviceWireless:RequestScan {} +--- If we scan we simply update the list that holds all access points +--- We can then get the list and create a new access point for all devices +---@param callback any +function WIRELESS:RequestScan(callback) + local ap_list = {} + self.NetworkManagerDeviceWireless:RequestScanAsync(function(_, _, _, failure) + for _, value in ipairs(self.NetworkManagerDeviceWireless:GetAllAccessPoints()) do + table.insert(ap_list, access_point(value)) + end + callback(ap_list) + end, { call_id = 'AMOGUS' }, {}) end return setmetatable(device, { - __call = function(self, device_path) + __call = function(_, device_path) + local self = gobject {} + gtable.crush(self, device, true) + self.object_path = device_path self.NetworkManagerDevice = dbus_proxy.Proxy:new { bus = dbus_proxy.Bus.SYSTEM, name = 'org.freedesktop.NetworkManager', @@ -51,9 +66,8 @@ return setmetatable(device, { self:emit_signal('NetworkManagerDevice::StateChanged', new_state, reason) end, 'StateChanged') - if self.NetworkManagerDevice.DeviceType == self.DeviceType.WIFI then - - gtable.crush(self, WIRELESS) + if self.NetworkManagerDevice.DeviceType == self._private.DeviceType.WIFI then + gtable.crush(self, WIRELESS, true) self.NetworkManagerDeviceWireless = dbus_proxy.Proxy:new { bus = dbus_proxy.Bus.SYSTEM, @@ -73,19 +87,35 @@ return setmetatable(device, { self:emit_signal('NetworkManagerDeviceWireless::Bitrate', data.Bitrate) end if data.ActiveAccessPoint then - self.emit_signal('NetworkManagerDeviceWireless::ActiveAccessPoint', data.ActiveAccessPoint) + self:emit_signal('NetworkManagerDeviceWireless::ActiveAccessPoint', self.current_ap, data.ActiveAccessPoint) + self.current_ap = data.ActiveAccessPoint end end, 'PropertiesChanged') + self.current_ap = self.NetworkManagerDeviceWireless.ActiveAccessPoint + self.ap_list = {} self.NetworkManagerDeviceWireless:connect_signal(function(_, path) - self:emit_signal('NetworkManagerDeviceWireless::AccessPointAdded', path) + --check if path is already in list + for _, value in ipairs(self.ap_list) do + if value == path then + return + end + end + table.insert(self.ap_list, path) + self:emit_signal('NetworkManagerDeviceWireless::AccessPointAdded', access_point(path)) end, 'AccessPointAdded') self.NetworkManagerDeviceWireless:connect_signal(function(_, path) self:emit_signal('NetworkManagerDeviceWireless::AccessPointRemoved', path) + for i, value in ipairs(self.ap_list) do + if value == path then + table.remove(self.ap_list, i) + return + end + end end, 'AccessPointRemoved') - elseif self.NetworkManagerDevice.DeviceType == self.DeviceType.ETHERNET then + elseif self.NetworkManagerDevice.DeviceType == self._private.DeviceType.ETHERNET then self.NetworkManagerDeviceWired = dbus_proxy.Proxy:new { bus = dbus_proxy.Bus.SYSTEM, @@ -108,25 +138,28 @@ return setmetatable(device, { self:emit_signal('NetworkManagerDeviceWired::Carrier', data.Carrier) end end, 'PropertiesChanged') - end + + setmetatable(self, { + __index = function(self, key) + if key == 'DeviceType' then + return self.NetworkManagerDevice.DeviceType + elseif key == 'State' then + return self.NetworkManagerDevice.State + elseif key == 'StateReason' then + return self.NetworkManagerDevice.StateReason + elseif key == 'Bitrate' then + if self.NetworkManagerDeviceWireless then + return self.NetworkManagerDeviceWireless.Bitrate + end + elseif key == 'Managed' then + return self.NetworkManagerDevice.Managed + elseif key == 'ActiveConnection' then + return self.NetworkManagerDevice.ActiveConnection + end + end, + }) + return self end, - __index = function(self, key) - if key == 'DeviceType' then - return self.NetworkManagerDevice.DeviceType - elseif key == 'State' then - return self.NetworkManagerDevice.State - elseif key == 'StateReason' then - return self.NetworkManagerDevice.StateReason - elseif key == 'Bitrate' then - if self.NetworkManagerDeviceWireless then - return self.NetworkManagerDeviceWireless.Bitrate - end - elseif key == 'Managed' then - return self.NetworkManagerDevice.Managed - elseif key == 'ActiveConnection' then - return self.NetworkManagerDevice.ActiveConnection - end - end, }) diff --git a/awesome/src/tools/network/init.lua b/awesome/src/tools/network/init.lua index e14640b..0c881aa 100644 --- a/awesome/src/tools/network/init.lua +++ b/awesome/src/tools/network/init.lua @@ -1,9 +1,11 @@ local lgi = require('lgi') local gobject = require('gears.object') +local NM = require('lgi').NM local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy') local nmdevice = require('src.tools.network.device') +local settings = require('src.tools.network.settings') local network = gobject {} @@ -39,17 +41,63 @@ network.DeviceState = { FAILED = 120, } -function network:toggle_network() - self._private.NetworkManager:Set('org.freedesktop.NetworkManager', 'NetworkingEnabled', lgi.GLib.Variant('b', not self.NetworkingEnabled)) +---Will try to connect to an access point by first searching if the connection already exists +--- and then adding the connection if its not. +---@param ap any +---@param connection any +---@param callback any +function network:ConnectToAccessPointAsync(ap, device, connection, callback) + print(ap, connection) + + for path, value in pairs(self.NetworkManagerSettings.ConnectionList or {}) do + print(--[[ connection.connection.id.value, ]] ap.SSID, value:GetSettings().connection.id) + if (connection and connection.connection.id.value or ap.SSID) == value:GetSettings().connection.id then + if connection then + value:Update(connection) + end + self.NetworkManager:ActivateConnectionAsync(function(_, _, succ, failure) + print(failure, succ) + if failure then + callback(false) + return + else + callback(true) + return + end + end, { call_id = 'amogus' }, path, device.object_path, ap.object_path) + return + end + end + + if not connection then + callback(false) + return + end + + self.NetworkManager:AddAndActivateConnectionAsync(function(_, _, succ, fail) + if fail then + callback(false) + return + else + callback(true) + return + end + end, { call_id = 'amogus' }, connection, device.object_path, ap.object_path) + end -function network:get_active_device() - for path, device in pairs(self.Devices) do - print(device.ActiveConnection, path) - if device.State == self.DeviceState.ACTIVATED then - print(device, path) - else - print('no active device') +function network:DisconnectFromAP() + self.NetworkManager:DeactivateConnection(self:get_wireless_device().ActiveConnection) +end + +--TODO: Make sure this works, I don't know how its going +--TODO: to work if there were multiple wireless devices, probably try +--TODO: to find the one that is active or something like that +function network:get_wireless_device() + for _, device in pairs(self.Devices) do + print(device.DeviceType, device.device_path) + if device.DeviceType == self.DeviceType.WIFI then + return device end end end @@ -60,16 +108,19 @@ function network:get_devices() for _, device in ipairs(devices) do self.Devices[device] = nmdevice(device) self.Devices[device]:connect_signal('NetworkManagerDevice::StateChanged', function(_, s, r) - print(device, s, r) end) end end +function network:toggle_network() + self.NetworkManager:Set('org.freedesktop.NetworkManager', 'NetworkingEnabled', lgi.GLib.Variant('b', not self.NetworkingEnabled)) +end + function network:toggle_wifi() - if not self.NetworkingEnabled then + if self.NetworkingEnabled == false then self:toggle_network() end - self._private.NetworkManager:Set('org.freedesktop.NetworkManager', 'WirelessEnabled', lgi.GLib.Variant('b', not self.NetworkingEnabled)) + self.NetworkManager:Set('org.freedesktop.NetworkManager', 'WirelessEnabled', lgi.GLib.Variant('b', not self.WirelessEnabled)) end local instance = nil @@ -90,12 +141,7 @@ if not instance then path = '/org/freedesktop/NetworkManager', } - self.NetworkManagerSettings = dbus_proxy.Proxy:new { - bus = dbus_proxy.Bus.SYSTEM, - name = 'org.freedesktop.NetworkManager', - interface = 'org.freedesktop.NetworkManager.Settings', - path = '/org/freedesktop/NetworkManager/Settings', - } + self.NetworkManagerSettings = settings() self.NetworkManager:connect_signal(function(_, device_path) if device_path then @@ -120,8 +166,17 @@ if not instance then end end, 'PropertiesChanged') + -- Init values because signal isn't emitted on startup + self:emit_signal('NetworkManager::WirelessEnabled', self.NetworkManager.WirelessEnabled) + self:emit_signal('NetworkManager::NetworkingEnabled', self.NetworkManager.NetworkingEnabled) + self.WirelessEnabled = self.NetworkManager.WirelessEnabled + self.NetworkingEnabled = self.NetworkManager.NetworkingEnabled + + self:get_devices() - self:get_active_device() + + + return self end, }) end diff --git a/awesome/src/tools/network/settings.lua b/awesome/src/tools/network/settings.lua new file mode 100644 index 0000000..67c0fa5 --- /dev/null +++ b/awesome/src/tools/network/settings.lua @@ -0,0 +1,136 @@ +local gobject = require('gears.object') +local gtable = require('gears.table') +local lgi = require('lgi') +local NM = require('lgi').NM + +local dbus_proxy = require('src.lib.lua-dbus_proxy.src.dbus_proxy') + +local settings = gobject {} + +---Get a connection path by uuid +---@param uuid string +---@return string connection_path +function settings:GetConnectionByUUID(uuid) + return self.NetworkManagerSettings:GetConnectionByUuid(uuid) or '' +end + +function settings:GetConnectionForSSID(ssid) + for _, con in pairs(self.ConnectionList) do + if con:GetSettings().connection.id == ssid then + return con + end + end +end + +--! For some reason not working, using AddAndActivateConnection instead works and adds the connection just fine +---Tries to add a new connection to the connections and returns the path if successfull +---@param con table connection +---@return string? +function settings:AddConnection(con) + --[[ local c = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = 'org.freedesktop.NetworkManager', + interface = 'org.freedesktop.NetworkManager.Settings.Connection', + path = '/org/freedesktop/NetworkManager/Settings/', + } ]] + + --[[ c:Update(con) + print('No Problem') + print(c:GetSettings().connection.id) ]] + --local path = self.NetworkManagerSettings:AddConnection(con) + --print(path) + --return path +end + +function settings:RemoveConnection(con) + if not con then return end + + con:Delete() +end + +---Returns a new and valid connection table +---@param args {passwd: string, security: string, autoconnect: boolean, ssid: string} +---@return table +function settings:NewConnectionProfile(args) + local security = {} + + if args.security:match('WPA') then + security = { + ['key-mgmt'] = lgi.GLib.Variant('s', 'wpa-psk'), + ['auth-alg'] = lgi.GLib.Variant('s', 'open'), + ['psk'] = lgi.GLib.Variant('s', args.passwd), + } + else + security = { + ['key-mgmt'] = lgi.GLib.Variant('s', 'wpa-psk'), + ['wep-key-type'] = lgi.GLib.Variant('s', NM.WepKeyType.PASSPHRASE), + ['wep-key0'] = lgi.GLib.Variant('s', args.passwd), + } + end + + return { + ['connection'] = { + ['uuid'] = lgi.GLib.Variant('s', string.gsub('xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx', '[xy]', function(c) + local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb) + return string.format('%x', v) + end)), + ['id'] = lgi.GLib.Variant('s', args.ssid), + ['type'] = lgi.GLib.Variant('s', '802-11-wireless'), + ['autoconnect'] = lgi.GLib.Variant('b', args.autoconnect), + }, + ['ipv4'] = { + ['method'] = lgi.GLib.Variant('s', 'auto'), + }, + ['ipv6'] = { + ['method'] = lgi.GLib.Variant('s', 'auto'), + }, + ['802-11-wireless'] = { + ['mode'] = lgi.GLib.Variant('s', 'infrastructure'), + }, + ['802-11-wireless-security'] = security, + } +end + +local instance = nil +if not instance then + instance = setmetatable(settings, { + __call = function(self) + self.NetworkManagerSettings = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = 'org.freedesktop.NetworkManager', + interface = 'org.freedesktop.NetworkManager.Settings', + path = '/org/freedesktop/NetworkManager/Settings', + } + + self.ConnectionList = {} + for _, value in pairs(self.NetworkManagerSettings:ListConnections()) do + local c = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = 'org.freedesktop.NetworkManager', + interface = 'org.freedesktop.NetworkManager.Settings.Connection', + path = value, + } + if c then self.ConnectionList[value] = c end + end + + self.NetworkManagerSettings:connect_signal(function(_, con) + print('New!', con) + local c = dbus_proxy.Proxy:new { + bus = dbus_proxy.Bus.SYSTEM, + name = 'org.freedesktop.NetworkManager', + interface = 'org.freedesktop.NetworkManager.Settings.Connection', + path = con, + } + self.ConnectionList[con] = c + end, 'NewConnection') + + self.NetworkManagerSettings:connect_signal(function(_, con) + print('Removed!', con) + self.ConnectionList[con] = nil + end, 'ConnectionRemoved') + + return self + end, + }) +end +return instance