generated from sendnrw/template_golang
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fee5b400a6 | |||
| 8e4325a1f8 |
109
main.go
109
main.go
@@ -10,6 +10,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
|
"os/exec"
|
||||||
"os/user"
|
"os/user"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"sort"
|
||||||
@@ -31,6 +32,7 @@ type NetInterface struct {
|
|||||||
MAC string `json:"mac"`
|
MAC string `json:"mac"`
|
||||||
Addresses []string `json:"addresses"`
|
Addresses []string `json:"addresses"`
|
||||||
IsLoopback bool `json:"is_loopback"`
|
IsLoopback bool `json:"is_loopback"`
|
||||||
|
Profile string `json:"profile"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type DiskInfo struct {
|
type DiskInfo struct {
|
||||||
@@ -206,6 +208,10 @@ func getInterfaces() []NetInterface {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Profile holen (best effort)
|
||||||
|
profilesByIndex, _ := getWinNetProfiles()
|
||||||
|
|
||||||
var out []NetInterface
|
var out []NetInterface
|
||||||
for _, ifc := range ifaces {
|
for _, ifc := range ifaces {
|
||||||
if (ifc.Flags & net.FlagUp) == 0 {
|
if (ifc.Flags & net.FlagUp) == 0 {
|
||||||
@@ -222,10 +228,7 @@ func getInterfaces() []NetInterface {
|
|||||||
case *net.IPAddr:
|
case *net.IPAddr:
|
||||||
ip = v.IP
|
ip = v.IP
|
||||||
}
|
}
|
||||||
if ip == nil {
|
if ip == nil || ip.IsLoopback() {
|
||||||
continue
|
|
||||||
}
|
|
||||||
if ip.IsLoopback() {
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
ips = append(ips, ip.String())
|
ips = append(ips, ip.String())
|
||||||
@@ -233,11 +236,15 @@ func getInterfaces() []NetInterface {
|
|||||||
if isLoop {
|
if isLoop {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
profile := profilesByIndex[ifc.Index] // 👈 jetzt sicher über Index
|
||||||
|
|
||||||
out = append(out, NetInterface{
|
out = append(out, NetInterface{
|
||||||
Name: ifc.Name,
|
Name: ifc.Name,
|
||||||
MAC: ifc.HardwareAddr.String(),
|
MAC: ifc.HardwareAddr.String(),
|
||||||
Addresses: ips,
|
Addresses: ips,
|
||||||
IsLoopback: isLoop,
|
IsLoopback: isLoop,
|
||||||
|
Profile: profile,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
@@ -358,25 +365,28 @@ var page = template.Must(template.New("index").Parse(`<!doctype html>
|
|||||||
h1{font-size:22px;margin:0 0 16px 0}
|
h1{font-size:22px;margin:0 0 16px 0}
|
||||||
.grid{display:flex;flex-direction:column;gap:12px}
|
.grid{display:flex;flex-direction:column;gap:12px}
|
||||||
.card{width:100%}
|
.card{width:100%}
|
||||||
.k{font-size:12px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
|
.k{font-size:16px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}
|
||||||
.v{font-weight:600}
|
.v{font-weight:600}
|
||||||
.row{display:flex;justify-content:space-between;gap:8px;align-items:center;margin:6px 0}
|
.row{display:flex;justify-content:space-between;gap:8px;align-items:center;margin:6px 0}
|
||||||
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}
|
.mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace}
|
||||||
.pill{display:inline-block;background:#0b2547;color:#b8d4ff;border-radius:999px;padding:2px 8px;margin:2px 6px 0 0;font-size:12px}
|
.stereo{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;color: #ffd500ff}
|
||||||
|
.pill{display:inline-block;background: #0b2547;color: #00ff2aff;border-radius:999px;padding:2px 8px;margin:2px 6px 0 0;font-size:14px}
|
||||||
|
.pill2{display:inline-block;background: #ffe100ff;color: #282828ff;border-radius:999px;padding:2px 8px;margin:2px 6px 0 0;font-size:14px}
|
||||||
.bar{height:10px;background:#091428;border-radius:999px;overflow:hidden}
|
.bar{height:10px;background:#091428;border-radius:999px;overflow:hidden}
|
||||||
.fill{height:100%;background:var(--accent);width:0%}
|
.fill{height:100%;background:var(--accent);width:0%}
|
||||||
footer{margin-top:18px;color:var(--muted);font-size:12px}
|
footer{margin-top:18px;color:var(--muted);font-size:12px}
|
||||||
.disks table{width:100%;border-collapse:collapse}
|
.disks table{width:100%;border-collapse:collapse}
|
||||||
.disks th,.disks td{padding:8px;border-bottom:1px solid #1b2a4a;text-align:left;font-size:14px}
|
.disks th,.disks td{padding:8px;border-bottom:1px solid #1b2a4a;text-align:left;font-size:14px}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Windows Systeminfo</h1>
|
<h1>Windows Systeminfo</h1>
|
||||||
<h2><div class="v mono" id="hostname2"></div></h2>
|
<h2><div class="v stereo" id="hostname2"></div></h2>
|
||||||
<div class="grid">
|
<div class="grid">
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<div class="k">Host</div>
|
<div class="k">Host</div>
|
||||||
<div class="row"><div>Hostname</div><div class="v mono" id="hostname"></div></div>
|
<div class="row"><div>Hostname</div><div class="v stereo" id="hostname"></div></div>
|
||||||
<div class="row"><div>User</div><div class="v mono" id="username"></div></div>
|
<div class="row"><div>User</div><div class="v mono" id="username"></div></div>
|
||||||
<div class="row"><div>Uptime</div><div class="v" id="uptime"></div></div>
|
<div class="row"><div>Uptime</div><div class="v" id="uptime"></div></div>
|
||||||
<div class="row"><div>Boot</div><div class="v" id="boottime"></div></div>
|
<div class="row"><div>Boot</div><div class="v" id="boottime"></div></div>
|
||||||
@@ -482,7 +492,14 @@ async function load(){
|
|||||||
(j.interfaces||[]).forEach(n=>{
|
(j.interfaces||[]).forEach(n=>{
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
div.innerHTML = '<div class="row"><div>'+n.name+'</div><div class="mono">'+(n.mac||'-')+'</div></div>';
|
div.innerHTML = '<div class="row"><div>'+n.name+'</div><div class="mono">'+(n.mac||'-')+'</div></div>';
|
||||||
|
if (n.profile) {
|
||||||
|
const p = document.createElement('span');
|
||||||
|
p.className = 'pill2';
|
||||||
|
p.textContent = n.profile;
|
||||||
|
div.appendChild(p);
|
||||||
|
}
|
||||||
(n.addresses||[]).forEach(ip=>{ const span=document.createElement('span'); span.className='pill mono'; span.textContent=ip; div.appendChild(span); });
|
(n.addresses||[]).forEach(ip=>{ const span=document.createElement('span'); span.className='pill mono'; span.textContent=ip; div.appendChild(span); });
|
||||||
|
|
||||||
wrap.appendChild(div);
|
wrap.appendChild(div);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -578,7 +595,7 @@ func runHTTP(ctx context.Context) error {
|
|||||||
mux.HandleFunc("/api/apps", appsHandler)
|
mux.HandleFunc("/api/apps", appsHandler)
|
||||||
mux.HandleFunc("/api/summary", apiHandler)
|
mux.HandleFunc("/api/summary", apiHandler)
|
||||||
|
|
||||||
addr := "127.0.0.1:8080"
|
addr := ":24000"
|
||||||
|
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
Addr: addr,
|
Addr: addr,
|
||||||
@@ -660,3 +677,77 @@ func main() {
|
|||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type psConnProfile struct {
|
||||||
|
Name string `json:"Name"`
|
||||||
|
InterfaceAlias string `json:"InterfaceAlias"`
|
||||||
|
InterfaceIndex int `json:"InterfaceIndex"`
|
||||||
|
NetworkCategory string `json:"NetworkCategory"` // "Public", "Private", "DomainAuthenticated"
|
||||||
|
}
|
||||||
|
|
||||||
|
func getWinNetProfiles() (map[int]string, error) {
|
||||||
|
cmd := exec.Command(
|
||||||
|
"powershell",
|
||||||
|
"-NoProfile",
|
||||||
|
"-NonInteractive",
|
||||||
|
"-Command",
|
||||||
|
`Get-NetConnectionProfile | Select-Object InterfaceAlias,InterfaceIndex,NetworkCategory | ConvertTo-Json -Depth 3`,
|
||||||
|
)
|
||||||
|
|
||||||
|
out, err := cmd.Output()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("getWinNetProfiles: powershell error: %v", err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(out) == 0 {
|
||||||
|
return map[int]string{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wir wissen nicht, ob PS ein Objekt oder ein Array zurückgibt → erst Array versuchen
|
||||||
|
type psConnProfile struct {
|
||||||
|
InterfaceAlias string `json:"InterfaceAlias"`
|
||||||
|
InterfaceIndex int `json:"InterfaceIndex"`
|
||||||
|
NetworkCategory interface{} `json:"NetworkCategory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
normalizeCat := func(v interface{}) string {
|
||||||
|
switch vv := v.(type) {
|
||||||
|
case string:
|
||||||
|
// "Public", "Private", "DomainAuthenticated"
|
||||||
|
return vv
|
||||||
|
case float64:
|
||||||
|
switch int(vv) {
|
||||||
|
case 0:
|
||||||
|
return "Public"
|
||||||
|
case 1:
|
||||||
|
return "Private"
|
||||||
|
case 2:
|
||||||
|
return "DomainAuthenticated"
|
||||||
|
default:
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1) Array probieren
|
||||||
|
var arr []psConnProfile
|
||||||
|
if err := json.Unmarshal(out, &arr); err == nil {
|
||||||
|
res := make(map[int]string, len(arr))
|
||||||
|
for _, p := range arr {
|
||||||
|
res[p.InterfaceIndex] = normalizeCat(p.NetworkCategory)
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) Einzelnes Objekt probieren
|
||||||
|
var single psConnProfile
|
||||||
|
if err := json.Unmarshal(out, &single); err != nil {
|
||||||
|
log.Printf("getWinNetProfiles: cannot unmarshal: %v -- out: %s", err, string(out))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
res := make(map[int]string, 1)
|
||||||
|
res[single.InterfaceIndex] = normalizeCat(single.NetworkCategory)
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user