Files
unifi-adblocker/config.go
T

197 lines
6.4 KiB
Go
Raw Normal View History

2025-12-06 07:47:30 +00:00
package main
import (
"encoding/json"
"fmt"
"log"
"os"
"sync"
"github.com/pquerna/otp/totp"
"golang.org/x/crypto/bcrypt"
)
type Config struct {
// Application
AppName string `json:"app_name"`
// Authentication
Username string `json:"username"`
HashedPass string `json:"hashed_password"`
MFASecret string `json:"mfa_secret"`
SessionTimeoutMins int `json:"session_timeout_minutes"`
// Server
Port string `json:"port"`
BindAddr string `json:"bind_address"`
// Blocklist settings
UpdateDelay int `json:"update_delay_days"`
CheckInterval int `json:"check_interval_seconds"`
// File paths
PidFile string `json:"pid_file"`
ProcessName string `json:"process_name"`
TmpFile string `json:"tmp_file"`
LastUpdateFile string `json:"last_update_file"`
URLFileList string `json:"url_file_list"`
BlocklistFile string `json:"blocklist_file"`
RemoveFile string `json:"remove_file"`
MergedListTmp string `json:"merged_list_tmp"`
// Default blocklist URLs
2025-12-06 09:06:39 +00:00
DefaultURLs []URLListItem `json:"default_urls"`
2025-12-06 07:47:30 +00:00
}
var (
config Config
configFile = "config.json"
configMu sync.RWMutex
)
func getDefaultConfig() Config {
return Config{
AppName: "Unifi Blocklist Manager",
Username: "admin",
HashedPass: "", // Will be set with hashed password
MFASecret: "",
SessionTimeoutMins: 60, // 1 hour default
Port: "8080",
BindAddr: "0.0.0.0",
UpdateDelay: 3,
CheckInterval: 5,
PidFile: "/tmp/coredns_last.pid",
ProcessName: "coredns",
TmpFile: "/sdcard1/combined-blocklist.txt",
LastUpdateFile: "/sdcard1/last_update.txt",
2025-12-06 09:06:39 +00:00
URLFileList: "/sdcard1/urllist.csv",
2025-12-06 07:47:30 +00:00
BlocklistFile: "/run/utm/domain_list/domainlist_0.list",
RemoveFile: "/run/utm/domain_list/domainlist_1.list",
MergedListTmp: "/tmp/mergedlist.txt",
2025-12-06 09:06:39 +00:00
DefaultURLs: []URLListItem{
{Name: "AdGuard DNS filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_27.txt"},
{Name: "AdGuard Russian filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_49.txt"},
{Name: "AdGuard Base filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt"},
{Name: "AdGuard Tracking Protection", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_42.txt"},
{Name: "AdGuard Social Media filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_18.txt"},
{Name: "AdGuard Annoyance filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_23.txt"},
{Name: "AdGuard Mobile Ads filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_11.txt"},
{Name: "AdGuard Search Ads filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_9.txt"},
{Name: "AdGuard Adult filter", Enabled: true, Group: "Default", URL: "https://adguardteam.github.io/HostlistsRegistry/assets/filter_50.txt"},
{Name: "AntiMalware Hosts", Enabled: true, Group: "Default", URL: "https://raw.githubusercontent.com/DandelionSprout/adfilt/master/Alternate%20versions%20Anti-Malware%20List/AntiMalwareHosts.txt"},
{Name: "DigitalSide Threat Intel", Enabled: true, Group: "Default", URL: "https://osint.digitalside.it/Threat-Intel/lists/latestdomains.txt"},
{Name: "Firebog Crypto", Enabled: true, Group: "Default", URL: "https://v.firebog.net/hosts/Prigent-Crypto.txt"},
{Name: "Phishing Army", Enabled: true, Group: "Default", URL: "https://phishing.army/download/phishing_army_blocklist_extended.txt"},
{Name: "W3kbl", Enabled: true, Group: "Default", URL: "https://v.firebog.net/hosts/static/w3kbl.txt"},
2025-12-06 07:47:30 +00:00
},
}
}
func loadConfig() {
configMu.Lock()
defer configMu.Unlock()
file, err := os.Open(configFile)
if err != nil {
log.Println("Config not found, creating default")
// Create default config with admin user
defaultConfig := getDefaultConfig()
hashed, _ := bcrypt.GenerateFromPassword([]byte("Password123!"), bcrypt.DefaultCost)
defaultConfig.HashedPass = string(hashed)
config = defaultConfig
saveConfigLocked()
log.Println("Default config created with admin/Password123!")
return
}
defer file.Close()
err = json.NewDecoder(file).Decode(&config)
if err != nil {
log.Printf("Error reading config: %v, using defaults", err)
defaultConfig := getDefaultConfig()
hashed, _ := bcrypt.GenerateFromPassword([]byte("Password123!"), bcrypt.DefaultCost)
defaultConfig.HashedPass = string(hashed)
config = defaultConfig
}
}
func saveConfigLocked() {
file, err := os.Create(configFile)
if err != nil {
log.Fatal(err)
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
err = encoder.Encode(config)
if err != nil {
log.Fatal(err)
}
}
func saveConfig() {
configMu.Lock()
defer configMu.Unlock()
saveConfigLocked()
}
func handleMFACommand(cmd string) {
switch cmd {
case "on":
configMu.Lock()
if config.MFASecret == "" {
// Generate new secret
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "UnifiBlocklist",
AccountName: config.Username,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Error generating MFA: %v\n", err)
configMu.Unlock()
os.Exit(1)
}
config.MFASecret = key.Secret()
saveConfigLocked()
fmt.Printf("MFA enabled.\nSecret: %s\nOTP URL: %s\n", key.Secret(), key.URL())
} else {
fmt.Println("MFA is already enabled")
configMu.Unlock()
return
}
configMu.Unlock()
case "off":
configMu.Lock()
if config.MFASecret != "" {
config.MFASecret = ""
saveConfigLocked()
fmt.Println("MFA disabled")
} else {
fmt.Println("MFA is not enabled")
}
configMu.Unlock()
case "reset":
configMu.Lock()
key, err := totp.Generate(totp.GenerateOpts{
Issuer: "UnifiBlocklist",
AccountName: config.Username,
})
if err != nil {
fmt.Fprintf(os.Stderr, "Error generating MFA: %v\n", err)
configMu.Unlock()
os.Exit(1)
}
config.MFASecret = key.Secret()
saveConfigLocked()
fmt.Printf("MFA reset.\nNew Secret: %s\nOTP URL: %s\nScan with your authenticator app.\n", key.Secret(), key.URL())
configMu.Unlock()
default:
fmt.Fprintf(os.Stderr, "Invalid MFA command. Use: on, off, or reset\n")
os.Exit(1)
}
}