mirror of
https://github.com/fumiama/go-nd-portal.git
synced 2026-06-05 00:10:25 +08:00
## Pull Request Overview
This PR enhances the login CLI to support a new “dorm area” and replaces the old `-x` flag with two new flags for server host (`-s`) and login type (`-t`).
- Introduces a `LoginType` enum and dynamic domain/AcID mapping in `Portal`.
- Refactors URL construction to use `go-querystring` and JSON-encoded user info.
- Updates tests and removes the hard-coded `-x` logic in `cmd/main.go`.
### Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.
<details>
<summary>Show a summary per file</summary>
| File | Description |
| ---------------------- | --------------------------------------------------------------- |
| portal/server_test.go | Updated tests to supply the new `loginType` parameter and use `GetUserInfo`. |
| portal/server.go | Reworked URL builders (`GetChallengeURL`, `GetLoginURL`), JSON `UserInfo`, and dynamic flags. |
| portal/portal.go | Added `LoginType`, `ToDomainAcID`, updated `NewPortal`, `GetChallenge`, and `Login` signatures. |
| cmd/main.go | Removed `-x`, added `-s`/`-t` flags, wired them through to `Portal`. |
| base64/base64.go | Fixed typo in package comment. |
| go.mod | Added `github.com/google/go-querystring` dependency. |
</details>
<details>
<summary>Comments suppressed due to low confidence (4)</summary>
**base64/base64.go:1**
* Typo in the comment: 'talbe' should be 'table'.
```
// Package base64 with customized talbe
```
**portal/portal.go:53**
* New login types (`qsh-dx`, `qshd-dx`, `qshd-cmcc`) were added but there are no unit tests verifying `ToDomainAcID` returns the correct domain and AC ID for each, or that invalid types produce an error. Consider adding tests for each mapping and an invalid case.
```
func (lt LoginType) ToDomainAcID() (string, string, error) {
```
**cmd/main.go:54**
* [nitpick] The flag variables `s` and `t` are not descriptive. Consider renaming them to `server` and `loginType` (or similar) to improve clarity for users and maintainers.
```
s := flag.String("s", portal.PortalServerIPQsh, "login host")
```
**cmd/main.go:106**
* The call to `netip.ParseAddr` requires importing the `net/netip` package, but `netip` is not imported. Add `import "net/netip"` to fix the compile error.
```
_, err := netip.ParseAddr(*s)
```
</details>
---------
Co-authored-by: 源文雨 <41315874+fumiama@users.noreply.github.com>
138 lines
2.7 KiB
Go
138 lines
2.7 KiB
Go
// Package cmd interacts with user
|
|
package cmd
|
|
|
|
import (
|
|
"flag"
|
|
"fmt"
|
|
"net"
|
|
"net/netip"
|
|
"os"
|
|
"runtime"
|
|
|
|
"golang.org/x/term"
|
|
|
|
"github.com/sirupsen/logrus"
|
|
|
|
"github.com/fumiama/go-nd-portal/helper"
|
|
"github.com/fumiama/go-nd-portal/portal"
|
|
)
|
|
|
|
func outip() (net.IP, error) {
|
|
conn, err := net.Dial("udp", "8.8.8.8:53")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_ = conn.Close()
|
|
return conn.LocalAddr().(*net.UDPAddr).IP.To4(), nil
|
|
}
|
|
|
|
func line() int {
|
|
_, _, fileLine, ok := runtime.Caller(1)
|
|
if ok {
|
|
return fileLine
|
|
}
|
|
return -1
|
|
}
|
|
|
|
const query = "query"
|
|
|
|
// Main cmd program
|
|
func Main() {
|
|
ip, err := outip()
|
|
ipf := ""
|
|
if err != nil {
|
|
ipf = query
|
|
} else {
|
|
ipf = ip.String()
|
|
}
|
|
ips := flag.String("ip", ipf, "public IP")
|
|
n := flag.String("n", query, "username")
|
|
p := flag.String("p", query, "password")
|
|
h := flag.Bool("h", false, "display this help")
|
|
w := flag.Bool("w", false, "only display warn-or-higher-level log")
|
|
d := flag.Bool("d", false, "display debug-level log")
|
|
s := flag.String("s", portal.PortalServerIPQsh, "login host")
|
|
t := flag.String("t", "qsh-edu", "login type [qsh-edu | qsh-dx | qshd-dx | qshd-cmcc]")
|
|
flag.Parse()
|
|
if *h {
|
|
fmt.Println("Usage:")
|
|
flag.PrintDefaults()
|
|
os.Exit(0)
|
|
}
|
|
if *d {
|
|
logrus.SetLevel(logrus.DebugLevel)
|
|
} else if *w {
|
|
logrus.SetLevel(logrus.WarnLevel)
|
|
}
|
|
if *ips == query {
|
|
fmt.Printf("ip: ")
|
|
_, err = fmt.Scanln(ips)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
}
|
|
if *ips != ip.String() {
|
|
ipaddr, err := netip.ParseAddr(*ips)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
a4 := ipaddr.As4()
|
|
copy(ip, a4[:])
|
|
}
|
|
if *n == query {
|
|
fmt.Printf("username: ")
|
|
_, err = fmt.Scanln(n)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
}
|
|
if *p == query {
|
|
fmt.Printf("password: ")
|
|
data, err := term.ReadPassword(int(os.Stdin.Fd()))
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
*p = helper.BytesToString(data)
|
|
fmt.Println()
|
|
}
|
|
logrus.Debugf("server addr: %s, login type: %s", *s, *t)
|
|
if *s != portal.PortalServerIPQsh {
|
|
// just validate IP here,
|
|
// dont convert to net.IP because we need only its string later
|
|
_, err := netip.ParseAddr(*s)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
}
|
|
// n : username
|
|
// p: password
|
|
// ip : public ip
|
|
// *t : login type
|
|
ptl, err := portal.NewPortal(*n, *p, ip, portal.LoginType(*t))
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
// input:
|
|
// server IP
|
|
challenge, err := ptl.GetChallenge(*s)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
// input:
|
|
// server IP
|
|
// challenge
|
|
err = ptl.Login(*s, challenge)
|
|
if err != nil {
|
|
logrus.Errorln(err)
|
|
os.Exit(line())
|
|
}
|
|
logrus.Infoln("success")
|
|
}
|