Skip to content

Commit

Permalink
Implement alternatives public access points configuration file
Browse files Browse the repository at this point in the history
From now on the user is able to configure alternatives WLAN access
points through the configuration file `/.eutherpe/wlan/pub-aps`,
saved in her/his music storage device.
  • Loading branch information
rafael-santiago committed Sep 26, 2024
1 parent d9b7457 commit f0bc9f2
Show file tree
Hide file tree
Showing 3 changed files with 190 additions and 13 deletions.
75 changes: 74 additions & 1 deletion src/internal/vars/vars.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,68 @@ func (e *EutherpeVars) GetCoversCacheRootPath() string {
return path.Join(e.ConfHome, EutherpeCoversHome)
}

func (e *EutherpeVars) hasPubAPs() bool {
pubAPsFilePath := path.Join(e.CachedDevices.MusicDevId,
EutherpeMusicDevRootDir,
EutherpeMusicDevWLANDir,
EutherpeMusicDevWLANPubApsFile)
_, err := os.Stat(pubAPsFilePath)
return (err == nil)
}

func (e *EutherpeVars) getAddrByPubAPs() error {
pubAPsFilePath := path.Join(e.CachedDevices.MusicDevId,
EutherpeMusicDevRootDir,
EutherpeMusicDevWLANDir,
EutherpeMusicDevWLANPubApsFile)
wlanCredentials, err := wifi.GetPlainWLANCredentials(pubAPsFilePath)
if err != nil {
return err
}
if len(wlanCredentials) == 0 {
return fmt.Errorf("No public credentials were found.")
}
wpaSupplicantConfFilePath := path.Join(os.TempDir(), "wpa_supplicant.conf")
for _, currCredential := range wlanCredentials {
wpaSupplicantConf, err := wifi.GetWPASupplicantConf(currCredential.ESSID, currCredential.Passphrase)
if err != nil {
continue
}
err = os.WriteFile(wpaSupplicantConfFilePath, []byte(wpaSupplicantConf), 0777)
if err != nil {
continue
}
e.HTTPd.Addr, err = e.connectToWLAN(wpaSupplicantConfFilePath)
if err == nil {
fmt.Printf("info: Public WLAN configured, trying to acquire a WLAN connection from '%s'... wait...\n", currCredential.ESSID)
break
}
}
return err
}

func (e *EutherpeVars) connectToWLAN(wpaSupplicantConfFilePath string) (string, error) {
var ipAddr string
wlanIfaces := wifi.GetIfaces()
err := fmt.Errorf("warn: No WLAN interface was found.\n")
if len(wlanIfaces) == 0 {
return "", err
} else {
wifi.SetIfaceUp(wlanIfaces[0])
time.Sleep(3 * time.Second)
e.WLAN.ConnSession, err = wifi.Start(wlanIfaces[0], wpaSupplicantConfFilePath)
if err == nil {
e.WLAN.Iface = wlanIfaces[0]
ipAddr, _ = wifi.LeaseAddr(wlanIfaces[0])
if len(ipAddr) == 0 {
wifi.Stop(e.WLAN.ConnSession)
e.WLAN.ConnSession = nil
}
}
}
return ipAddr, err
}

func (e *EutherpeVars) SetAddr() error {
ifaces, err := net.Interfaces()
if err != nil {
Expand Down Expand Up @@ -404,8 +466,16 @@ func (e *EutherpeVars) SetAddr() error {
break
}
}
if len(e.WLAN.ESSID) > 0 {
wlanAddrConfigured := false
if e.hasPubAPs() {
err := e.getAddrByPubAPs()
wlanAddrConfigured = (err == nil)
}
if !wlanAddrConfigured && len(e.WLAN.ESSID) > 0 {
fmt.Printf("info: WLAN is configured, trying to acquire a WLAN connection... wait...\n")
e.HTTPd.Addr, err = e.connectToWLAN(wifi.WPASupplicantConfFilePath)
fmt.Printf("info: Eutherpe has ingressed to the WLAN %s.\n", e.WLAN.ESSID)
/*
wlanIfaces := wifi.GetIfaces()
if len(wlanIfaces) == 0 {
fmt.Printf("warn: No WLAN interface was found.\n")
Expand All @@ -425,6 +495,7 @@ func (e *EutherpeVars) SetAddr() error {
}
}
}
*/
}
if len(e.HTTPd.Addr) == 0 && !hasRescueIface {
return fmt.Errorf("Unable to set a valid IP")
Expand Down Expand Up @@ -695,6 +766,8 @@ const EutherpeGateTemplate = 2

const EutherpeMusicDevRootDir = ".eutherpe"
const EutherpeMusicDevPlaylistsDir = "playlists"
const EutherpeMusicDevWLANDir = "wlan"
const EutherpeMusicDevWLANPubApsFile = "pub-aps"

const EutherpeOptionListenPort = "listen-port"

Expand Down
92 changes: 81 additions & 11 deletions src/internal/wifi/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,15 @@ import (
"fmt"
)

const (
WPASupplicantConfFilePath = "/etc/wpa_supplicant/wpa_supplicant.conf"
)

type WLANPlainCredential struct {
ESSID string
Passphrase string
}

func GetIfaces(customPath ...string) []string {
out, err := exec.Command(path.Join(getToolPath(customPath...), "ip"), "link", "show").CombinedOutput()
if err != nil {
Expand Down Expand Up @@ -42,13 +51,21 @@ func SetIfaceDown(ifaceName string, customPath ...string) error {
return exec.Command("sudo", path.Join(getToolPath(customPath...), "ip"), "link", "set", "dev", ifaceName, "down").Run()
}

func SetWPAPassphrase(ESSID, passphrase string, customPath ...string) error {
out, err := exec.Command(path.Join(getToolPath(customPath...), "wpa_passphrase"), ESSID, passphrase).CombinedOutput()
if err != nil {
return err
func GetWPASupplicantConf(ESSID, passphrase string, customPath ...string) (string, error) {
var credentials string
var keyMgmt string
if len(passphrase) > 0 {
out, err := exec.Command(path.Join(getToolPath(customPath...), "wpa_passphrase"), ESSID, passphrase).CombinedOutput()
if err != nil {
return "", err
}
sOut := strings.Split(string(out), "\n")
credentials = sOut[1] + "\n" + sOut[3] + "\n"
keyMgmt = "WPA-PSK"
} else {
credentials = "ssid=\"" + ESSID + "\""
keyMgmt = "NONE"
}
sOut := strings.Split(string(out), "\n")
credentials := sOut[1] + "\n" + sOut[3] + "\n"
wpaSupplicantConf := `ctrl_interface=/run/wpa_supplicant
fast_reauth=1
#ap_scan=1
Expand All @@ -57,18 +74,27 @@ fast_reauth=1
network={
scan_ssid=0
proto=WPA
key_mgmt=WPA-PSK
key_mgmt={{.KEY-MGMT}}
auth_alg=OPEN
{{.CREDENTIALS}}
}
`
wpaSupplicantConf = strings.Replace(wpaSupplicantConf, "{{.CREDENTIALS}}", credentials, -1)
return os.WriteFile("/etc/wpa_supplicant/wpa_supplicant.conf", []byte(wpaSupplicantConf), 0777)
wpaSupplicantConf = strings.Replace(wpaSupplicantConf, "{{.KEY-MGMT}}", keyMgmt, 1)
wpaSupplicantConf = strings.Replace(wpaSupplicantConf, "{{.CREDENTIALS}}", credentials, 1)
return wpaSupplicantConf, nil
}

func Start(ifaceName string, customPath ...string) (*exec.Cmd, error) {
func SetWPAPassphrase(ESSID, passphrase string, customPath ...string) error {
confData, err := GetWPASupplicantConf(ESSID, passphrase, customPath...)
if err != nil {
return err
}
return os.WriteFile(WPASupplicantConfFilePath, []byte(confData), 0777)
}

func Start(ifaceName, wpaSupplicantConfFilePath string, customPath ...string) (*exec.Cmd, error) {
exec.Command("sudo", path.Join(getToolPath(customPath...), "systemctl"), "stop", "wpa_supplicant").Run()
procHandle := exec.Command("sudo", path.Join(getToolPath(customPath...), "wpa_supplicant"), "-c", "/etc/wpa_supplicant/wpa_supplicant.conf", "-i", ifaceName)
procHandle := exec.Command("sudo", path.Join(getToolPath(customPath...), "wpa_supplicant"), "-c", wpaSupplicantConfFilePath, "-i", ifaceName)
return procHandle, procHandle.Start()
}

Expand Down Expand Up @@ -112,6 +138,50 @@ func ReleaseAddr(ifaceName string, customPath... string) error {
return exec.Command(path.Join(getToolPath(customPath...), "dhclient"), "-r", ifaceName).Run()
}

func GetPlainWLANCredentials(plainCredentialsFilePath string) ([]WLANPlainCredential, error) {
blob, err := os.ReadFile(plainCredentialsFilePath)
plainCredentials := make([]WLANPlainCredential, 0)
if err != nil {
return plainCredentials, err
}
sBlob := string(blob)
sBlob = strings.Replace(sBlob, "\r", "", -1)
lines := strings.Split(sBlob, "\n")
for _, line := range lines {
shouldSkip := false
for _, l := range line {
if l == ' ' || l == '\t' {
continue
} else {
shouldSkip = (l == '#')
break
}
}
if shouldSkip {
continue
}
tokOff := len(line) - 1
for ; tokOff > 0; tokOff-- {
if line[tokOff] == ' ' || line[tokOff] == '\t' {
break
}
}
var ESSID string
var pass string
if tokOff > 0 && (tokOff+1) < len(line) {
pass = line[tokOff+1:]
} else {
tokOff = len(line)
}
ESSID = line[:tokOff]
if len(ESSID) == 0 {
continue
}
plainCredentials = append(plainCredentials, WLANPlainCredential { ESSID, pass })
}
return plainCredentials, nil
}

func getToolPath(customPath ...string) string {
if len(customPath) > 0 {
return customPath[0]
Expand Down
36 changes: 35 additions & 1 deletion src/internal/wifi/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,38 @@ func TestGetIfaces(t *testing.T) {
} else if ifaces[0] != "wlxf0a7314a4543" {
t.Errorf("GetIfaces() has returned an unexpected interface.\n")
}
}
}

func TestGetPlainWLANCredentials(t *testing.T) {
testData := "# ESSID PASSPHRASE\n" +
"Xablau 1234\n\n\r\n\n\n" +
"OpenedOne\r\n" +
"AbcD 42\r\n" +
"Teste com espacos 424242!"
err := os.WriteFile("/tmp/pub-aps", []byte(testData), 0777)
if err != nil {
t.Errorf("Unable to create /tmp/pub-aps")
} else {
defer os.Remove("/tmp/pub-aps")
credentials, err := GetPlainWLANCredentials("/tmp/pub-aps")
if err != nil {
t.Errorf("GetPlainWLANCredentials() returned and error : '%s'.\n", err.Error())
}
if len(credentials) != 4 {
t.Errorf("GetPlainWLANCredentials() returned a wrong total of credentials.\n")
}
if credentials[0].ESSID != "Xablau" || credentials[0].Passphrase != "1234" {
t.Errorf("credentials[0] has unexpected configuration.\n")
}
if credentials[1].ESSID != "OpenedOne" || credentials[1].Passphrase != "" {
t.Errorf("credentials[1] has unexpected configuration.\n")
}
if credentials[2].ESSID != "AbcD" || credentials[2].Passphrase != "42" {
t.Errorf("credentials[2] has unexpected configuration.\n")
}
if credentials[3].ESSID != "Teste com espacos" ||
credentials[3].Passphrase != "424242!" {
t.Errorf("credentials[3] has unexpected configuration.\n")
}
}
}

0 comments on commit f0bc9f2

Please sign in to comment.