diff --git a/Makefile b/Makefile index 1359610..278134f 100644 --- a/Makefile +++ b/Makefile @@ -50,10 +50,6 @@ pkg/wg-manager: pkg/wg-manager/cmd/register.go pkg/wg-manager/cmd/main.go pkg/wg server.iso: server.yml students.csv ssl/fullchain.pem ssl/privkey.pem challenge-initrd.img pkg/arp-spoofer pkg/login-validator pkg/monit pkg/postfix pkg/tftpd pkg/unbound pkg/wg-manager challenge-kernel login-initrd.img linuxkit build -docker -format iso-bios $< -pkg/debian-tuto2: pkg/debian-tuto2/sshd_config pkg/debian-tuto2/gai.conf pkg/debian-tuto2/isolinux.cfg pkg/debian-tuto2/build.yml pkg/debian-tuto2/default.script pkg/debian-tuto2/issue pkg/debian-tuto2/Dockerfile - linuxkit pkg build -org nemunaire pkg/debian-tuto2/ - touch pkg/debian-tuto2 - tuto2-kernel: tuto2.yml linuxkit build -docker $< tuto2-initrd.img: tuto2.yml @@ -61,7 +57,7 @@ tuto2-initrd.img: tuto2.yml tuto2-cmdline: tuto2.yml linuxkit build -docker $< -tuto2.iso: tuto2.yml pkg/debian-tuto2 tuto2-kernel tuto2-initrd.img tuto2-cmdline +tuto2.iso: tuto2.yml tuto2-kernel tuto2-initrd.img tuto2-cmdline linuxkit build -docker -format iso-bios $< tuto2-srs.iso: tuto2.iso pkg/debian-tuto2/isolinux.cfg diff --git a/checker/checker.go b/checker/checker.go index 5d510aa..ddddaad 100644 --- a/checker/checker.go +++ b/checker/checker.go @@ -1,14 +1,12 @@ package main import ( - "encoding/json" "errors" "fmt" "io/ioutil" "log" "net" "net/http" - "strings" "time" "github.com/miekg/dns" @@ -17,10 +15,6 @@ import ( "git.nemunai.re/lectures/adlin/libadlin" ) -const ( - DEFAULT_RESOLVER = "2a01:e0a:2b:2250::1" -) - var verbose = false // ICMP @@ -31,7 +25,6 @@ func check_ping(ip string, cb func(pkt *ping.Packet)) (err error) { if err != nil { return } - defer pinger.Stop() pinger.Timeout = time.Second * 5 pinger.Count = 1 @@ -53,7 +46,7 @@ func get_GLUE(domain string) (aaaa net.IP, err error) { m.SetEdns0(4096, true) var r *dns.Msg - r, _, err = client.Exchange(m, "[2a01:e0a:2b:2250::b]:53") + r, _, err = client.Exchange(m, "[2a01:e0a:25a:9160::2]:53") if err != nil { return } @@ -93,10 +86,8 @@ func check_dns(domain, ip string) (aaaa net.IP, err error) { err = errors.New("failed to get a valid answer") } - for _, answer := range r.Answer { - if t, ok := answer.(*dns.AAAA); ok { - aaaa = t.AAAA - } + if len(r.Answer) > 0 { + aaaa = r.Answer[0].(*dns.AAAA).AAAA } return @@ -104,33 +95,19 @@ func check_dns(domain, ip string) (aaaa net.IP, err error) { // PORT 80 -func check_http(ip, dn string) (err error) { +func check_http(ip string) (err error) { client := &http.Client{ CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse }, } - req, errr := http.NewRequest("GET", fmt.Sprintf("http://[%s]/", ip), nil) - if errr != nil { - return errr - } - - if dn != "" { - req.Header.Add("Host", strings.TrimSuffix(dn, ".")) - } - var resp *http.Response - resp, err = client.Do(req) + resp, err = client.Get(fmt.Sprintf("http://[%s]/", ip)) if err != nil { return } defer resp.Body.Close() - - if dn != "" && resp.StatusCode >= 400 { - return fmt.Errorf("Bad status, got: %d (%s)", resp.StatusCode, resp.Status) - } - _, err = ioutil.ReadAll(resp.Body) return } @@ -139,97 +116,18 @@ func check_http(ip, dn string) (err error) { func check_https(domain, ip string) (err error) { var resp *http.Response - resp, err = http.Get(fmt.Sprintf("https://%s/", strings.TrimSuffix(domain, "."))) + resp, err = http.Get(fmt.Sprintf("https://%s/", domain)) if err != nil { return } defer resp.Body.Close() - - if resp.StatusCode >= 300 && resp.StatusCode < 400 { - loc := resp.Header.Get("Location") - if loc != "" && strings.HasSuffix(dns.Fqdn(loc), domain) { - if dns.Fqdn(loc) == domain { - return fmt.Errorf("Redirection loop %s redirect to %s", domain, loc) - } else if err = check_https(dns.Fqdn(loc), ip); err != nil { - return fmt.Errorf("Error after following redirection to %s: %w", loc, err) - } else { - return - } - } - } - - if resp.StatusCode >= 300 { - return fmt.Errorf("Bad status, got: %d (%s)", resp.StatusCode, resp.Status) - } - _, err = ioutil.ReadAll(resp.Body) return } -// MATRIX - -type matrix_result struct { - WellKnownResult struct { - Result string `json:"result"` - } - DNSResult struct { - SRVError *struct { - Message string - } - } - ConnectionReports map[string]struct { - Errors []string - } - ConnectionErrors map[string]struct { - Message string - } - Version struct { - Name string `json:"name"` - Version string `json:"version"` - } - FederationOK bool -} - -func check_matrix(domain string) (version string, err error) { - var resp *http.Response - resp, err = http.Get(fmt.Sprintf("https://federation-tester.adlin.nemunai.re/api/report?server_name=%s", strings.TrimSuffix(domain, "."))) - if err != nil { - return - } - defer resp.Body.Close() - - if resp.StatusCode >= 300 { - return "", fmt.Errorf("Sorry, the federation tester is broken. Check on https://federationtester.matrix.org/#%s", domain) - } - - var federationTest matrix_result - if federationTest.FederationOK { - version = federationTest.Version.Name + " " + federationTest.Version.Version - return version, nil - } else if err = json.NewDecoder(resp.Body).Decode(&federationTest); err != nil { - log.Printf("Error in chech_matrix, when decoding json:", err.Error()) - return "", fmt.Errorf("Sorry, the federation tester is broken. Check on https://federationtester.matrix.org/#%s", domain) - } else if federationTest.DNSResult.SRVError != nil && federationTest.WellKnownResult.Result != "" { - return "", fmt.Errorf("%s OR %s", federationTest.DNSResult.SRVError.Message, federationTest.WellKnownResult.Result) - } else if len(federationTest.ConnectionErrors) > 0 { - var msg strings.Builder - for srv, cerr := range federationTest.ConnectionErrors { - if msg.Len() > 0 { - msg.WriteString("; ") - } - msg.WriteString(srv) - msg.WriteString(": ") - msg.WriteString(cerr.Message) - } - return "", fmt.Errorf("Connection errors: %s", msg.String()) - } else { - return "", fmt.Errorf("An unimplemented error occurs. Please report to nemunaire. But know that federation seems to be broken. Check https://federationtester.matrix.org/#%s", domain) - } -} - // Main -func minTunnelVersion(std *adlin.Student, suffixip int) (int, error) { +func minTunnelVersion(std adlin.Student) (int, error) { tunnels, err := std.GetTunnelTokens() if err != nil { return 0, err @@ -241,7 +139,7 @@ func minTunnelVersion(std *adlin.Student, suffixip int) (int, error) { continue } - if tunnel.Dump != nil && tunnel.Version < minversion && suffixip == tunnel.SuffixIP { + if tunnel.Dump != nil && tunnel.Version < minversion { minversion = tunnel.Version } } @@ -255,175 +153,110 @@ func studentsChecker() { log.Println("Unable to check students:", err) return } - check_matrix_for := (time.Now().Second()/30)*5 + time.Now().Minute()%5 + log.Println("Checking students...") - log.Printf("Checking students... (std_matrix%%10=%d)\n", check_matrix_for) - - for istd, s := range students { + for _, s := range students { time.Sleep(250 * time.Millisecond) // Check ping std := s - tuns, err := std.GetActivesTunnels() - if err != nil { - continue - } + stdIP := adlin.StudentIP(std.Id).String() + "1" + go check_ping(stdIP, func(pkt *ping.Packet) { + tunnel_version, err := minTunnelVersion(std) + if verbose { + log.Printf("%s PONG; version=%d (%v)\n", std.Login, tunnel_version, err) + } + std.OnPong(true) + + if tunnel_version == 2147483647 || tunnel_version == 0 { + log.Printf("%s unknown tunnel version: %d skipping tests (%v)", std.Login, tunnel_version, err) + return + } + + dnsIP := stdIP + // Is GLUE defined? + if glueIP, err := get_GLUE(std.MyDelegatedDomain()); glueIP != nil { + dnsIP = glueIP.String() - for _, tun := range tuns { - stdIP := tun.GetStudentIP() - go check_ping(stdIP, func(pkt *ping.Packet) { - tunnel_version, err := minTunnelVersion(std, tun.SuffixIP) if verbose { - log.Printf("%s PONG (on %x); version=%d (%v)\n", std.Login, tun.SuffixIP, tunnel_version, err) + log.Printf("%s has defined GLUE: %s\n", std.Login, dnsIP) } - std.OnPong(true) + } else if err != nil { + log.Printf("%s and GLUE: %s\n", std.Login, err) + } - if tunnel_version == 2147483647 || tunnel_version == 0 { - log.Printf("%s unknown tunnel version: %d skipping tests (%v)", std.Login, tunnel_version, err) - return + // Check DNS + if addr, err := check_dns(std.MyDelegatedDomain(), dnsIP); err == nil { + if verbose { + log.Printf("%s just unlocked DNS challenge\n", std.Login) } - - dnsIP := stdIP - var glueErr error - // Is GLUE defined? - if glueIP, err := get_GLUE(std.MyDelegatedDomain()); glueIP != nil { - dnsIP = glueIP.String() - - if verbose { - log.Printf("%s has defined GLUE: %s\n", std.Login, dnsIP) - } - } else if err != nil { - log.Printf("%s and GLUE: %s\n", std.Login, err) - glueErr = err - } - - // Check DNS - if addr, err := check_dns(std.MyDelegatedDomain(), dnsIP); err == nil { - if addr == nil { - dnsAt := " at " + dnsIP - if glueErr != nil { - dnsAt = " + there is a problem with the GLUE record: " + glueErr.Error() - } - if errreg := std.RegisterChallengeError(100*(tunnel_version-1)+3, fmt.Errorf("%s: empty response from the server%s", std.MyDelegatedDomain(), dnsAt)); errreg != nil { - log.Printf("Unable to register challenge error for %s: %s\n", std.Login, errreg) - } - } else { - if verbose { - log.Printf("%s just unlocked DNS challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+3, addr.String()); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } - - // Check HTTP with DNS - if glueErr != nil { - std.RegisterChallengeError(100*(tunnel_version-1)+4, fmt.Errorf("Unable to perform the test due to GLUE problem: %w", err)) - } else if err := check_http(addr.String(), std.MyDelegatedDomain()); err == nil { - if verbose { - log.Printf("%s just unlocked HTTP challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+4, ""); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } - } else { - std.RegisterChallengeError(100*(tunnel_version-1)+4, err) - if verbose { - log.Printf("%s and HTTP (with DNS ip=%s): %s\n", std.Login, addr.String(), err) - } - } - - // Check HTTPs with DNS - if glueErr != nil { - std.RegisterChallengeError(100*(tunnel_version-1)+5, fmt.Errorf("Unable to perform the test due to GLUE problem: %w", err)) - } else if err := check_https(std.MyDelegatedDomain(), addr.String()); err == nil { - if verbose { - log.Printf("%s just unlocked HTTPS challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+5, ""); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } - } else { - std.RegisterChallengeError(100*(tunnel_version-1)+5, err) - if verbose { - log.Printf("%s and HTTPS (with DNS ip=%s): %s\n", std.Login, addr.String(), err) - } - } - - // Check Matrix (only if GLUE Ok and) - if glueErr == nil && istd%10 == check_matrix_for { - if v, err := check_matrix(std.MyDelegatedDomain()); err == nil { - if verbose { - log.Printf("%s just unlocked Matrix challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+6, v); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } - } else { - std.RegisterChallengeError(100*(tunnel_version-1)+6, err) - if verbose { - log.Printf("%s and Matrix: %s\n", std.Login, err) - } - } - } - } - } else { - if errreg := std.RegisterChallengeError(100*(tunnel_version-1)+3, err); errreg != nil { - log.Printf("Unable to register challenge error for %s: %s\n", std.Login, errreg) - } - if verbose { - log.Printf("%s and DNS: %s\n", std.Login, err) - } - } - - // Check HTTP without DNS - if err := check_http(stdIP, ""); err == nil { - if verbose { - log.Printf("%s just unlocked HTTP IP (without DNS) challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+0, ""); err != nil { + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+2, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+2, ""); err != nil { log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) } - } else { - std.RegisterChallengeError(100*(tunnel_version-1)+0, err) + } + + // Check HTTP with DNS + if addr == nil { + log.Printf("%s and HTTP (with DNS ip=%s): skipped due to empty response\n", std.Login, addr.String()) + } else if err := check_http(addr.String()); err == nil { if verbose { - log.Printf("%s and HTTP IP (without DNS): %s\n", std.Login, err) + log.Printf("%s just unlocked HTTP challenge\n", std.Login) } - } - - // Check DNS for association - if addr, err := check_dns(std.MyAssociatedDomain(), DEFAULT_RESOLVER); err == nil { - // Check HTTP on delegated domain - if err := check_http(addr.String(), std.MyAssociatedDomain()); err == nil { - if verbose { - log.Printf("%s just unlocked HTTP (without DNS) challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+1, ""); err != nil { + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+0, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+0, ""); err != nil { log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) } - } else { - std.RegisterChallengeError(100*(tunnel_version-1)+1, err) - if verbose { - log.Printf("%s and HTTP (without DNS): %s\n", std.Login, err) - } - } - - // Check HTTPs without DNS - if err := check_https(std.MyAssociatedDomain(), stdIP); err == nil { - if verbose { - log.Printf("%s just unlocked HTTPS challenge\n", std.Login) - } - if _, err := std.UnlockChallenge(100*(tunnel_version-1)+2, ""); err != nil { - log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) - } - } else { - std.RegisterChallengeError(100*(tunnel_version-1)+2, err) - if verbose { - log.Printf("%s and HTTPS (without DNS): %s\n", std.Login, err) - } } + } else if verbose { + log.Printf("%s and HTTP (with DNS ip=%s): %s\n", std.Login, addr.String(), err) } - return - }) - } + // Check HTTPs with DNS + if addr == nil { + log.Printf("%s and HTTPS (with DNS ip=%s): skipped due to empty response\n", std.Login, addr.String()) + } else if err := check_https(std.MyDelegatedDomain(), addr.String()); err == nil { + if verbose { + log.Printf("%s just unlocked HTTPS challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+1, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+1, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTPS (with DNS ip=%s): %s\n", std.Login, addr.String(), err) + } + } else { + // Check HTTP without DNS + if err := check_http(stdIP); err == nil { + if verbose { + log.Printf("%s just unlocked HTTP challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+0, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+0, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTP (without DNS): %s\n", std.Login, err) + } + + // Check HTTPs without DNS + if err := check_https(std.MyAssociatedDomain(), stdIP); err == nil { + if verbose { + log.Printf("%s just unlocked HTTPS challenge\n", std.Login) + } + if _, err := std.UnlockNewChallenge(100*(tunnel_version-1)+1, ""); err != nil { + if _, err := std.UpdateUnlockedChallenge(100*(tunnel_version-1)+1, ""); err != nil { + log.Printf("Unable to register challenge for %s: %s\n", std.Login, err.Error()) + } + } + } else if verbose { + log.Printf("%s and HTTPS (without DNS): %s\n", std.Login, err) + } + } + + return + }) } } diff --git a/libadlin/db.go b/libadlin/db.go index 5fafcc9..44551f1 100644 --- a/libadlin/db.go +++ b/libadlin/db.go @@ -56,9 +56,7 @@ func DBCreate() (err error) { CREATE TABLE IF NOT EXISTS students( id_student INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, login VARCHAR(255) NOT NULL UNIQUE, - time TIMESTAMP NOT NULL, - associatedDomain VARCHAR(255) UNIQUE, - delegatedDomain VARCHAR(255) UNIQUE + time TIMESTAMP NOT NULL ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return @@ -95,19 +93,6 @@ CREATE TABLE IF NOT EXISTS student_challenges( CONSTRAINT token_found UNIQUE (id_student,challenge), FOREIGN KEY(id_student) REFERENCES students(id_student) ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; -`); err != nil { - return err - } - if _, err := db.Exec(` -CREATE TABLE IF NOT EXISTS student_challenge_errors( - id_st INTEGER NOT NULL PRIMARY KEY AUTO_INCREMENT, - id_student INTEGER NOT NULL, - challenge INTEGER NOT NULL, - time TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, - error VARCHAR(255) NOT NULL, - CONSTRAINT token_found UNIQUE (id_student,challenge), - FOREIGN KEY(id_student) REFERENCES students(id_student) -) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err } diff --git a/libadlin/domain.go b/libadlin/domain.go index 4553012..4a88dd2 100644 --- a/libadlin/domain.go +++ b/libadlin/domain.go @@ -6,39 +6,22 @@ import ( ) const ( - AssociatedDomainSuffix = "adlin2022.p0m.fr." + AssociatedDomainSuffix = "adlin2021.p0m.fr." DelegatedDomainSuffix = "srs.p0m.fr." ) -func (student *Student) MyDelegatedDomain() string { - if student.DelegatedDomain != nil { - return *student.DelegatedDomain - } else { - return fmt.Sprintf("%s.%s", strings.Trim(strings.Replace(student.Login, "_", "-", -1), "-_"), DelegatedDomainSuffix) - } +func (student Student) MyDelegatedDomain() string { + return fmt.Sprintf("%s.%s", strings.Trim(strings.Replace(student.Login, "_", "-", -1), "-_"), DelegatedDomainSuffix) } -func (student *Student) DefaultAssociatedDomain() string { +func (student Student) MyAssociatedDomain() string { return fmt.Sprintf("%s.%s", strings.Trim(strings.Replace(student.Login, "_", "-", -1), "-_"), AssociatedDomainSuffix) } -func (student *Student) MyAssociatedDomain() string { - if student.AssociatedDomain != nil { - return *student.AssociatedDomain - } else { - return student.DefaultAssociatedDomain() - } -} - -func (student *Student) GetAssociatedDomains() (ds []string) { - defdn := student.DefaultAssociatedDomain() - ds = append(ds, defdn) - +func (student Student) GetAssociatedDomains() (ds []string) { studentDomain := student.MyAssociatedDomain() - if defdn != studentDomain { - ds = append(ds, studentDomain) - } + ds = append(ds, studentDomain) return } diff --git a/libadlin/ping.go b/libadlin/ping.go index a93fc9c..c8bef5a 100644 --- a/libadlin/ping.go +++ b/libadlin/ping.go @@ -9,14 +9,14 @@ type Pong struct { State bool } -func (s *Student) LastPongs() (pongs []*Pong, err error) { +func (s Student) LastPongs() (pongs []Pong, err error) { if rows, errr := DBQuery("SELECT time, state FROM student_pong WHERE id_student = ? ORDER BY time DESC", s.Id); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - p := &Pong{} + var p Pong if err = rows.Scan(&p.Date, &p.State); err != nil { return } diff --git a/libadlin/session.go b/libadlin/session.go index 2665987..933f425 100644 --- a/libadlin/session.go +++ b/libadlin/session.go @@ -11,41 +11,40 @@ type Session struct { Time time.Time `json:"time"` } -func GetSession(id []byte) (s *Session, err error) { - s = new(Session) +func GetSession(id []byte) (s Session, err error) { err = DBQueryRow("SELECT id_session, id_student, time FROM student_sessions WHERE id_session=?", id).Scan(&s.Id, &s.IdStudent, &s.Time) return } -func NewSession() (*Session, error) { +func NewSession() (Session, error) { session_id := make([]byte, 255) if _, err := rand.Read(session_id); err != nil { - return nil, err + return Session{}, err } else if _, err := DBExec("INSERT INTO student_sessions (id_session, time) VALUES (?, ?)", session_id, time.Now()); err != nil { - return nil, err + return Session{}, err } else { - return &Session{session_id, nil, time.Now()}, nil + return Session{session_id, nil, time.Now()}, nil } } -func (student *Student) NewSession() (*Session, error) { +func (student Student) NewSession() (Session, error) { session_id := make([]byte, 255) if _, err := rand.Read(session_id); err != nil { - return nil, err + return Session{}, err } else if _, err := DBExec("INSERT INTO student_sessions (id_session, id_student, time) VALUES (?, ?, ?)", session_id, student.Id, time.Now()); err != nil { - return nil, err + return Session{}, err } else { - return &Session{session_id, &student.Id, time.Now()}, nil + return Session{session_id, &student.Id, time.Now()}, nil } } -func (s *Session) SetStudent(student *Student) (*Session, error) { +func (s Session) SetStudent(student Student) (Session, error) { s.IdStudent = &student.Id _, err := s.Update() return s, err } -func (s *Session) Update() (int64, error) { +func (s Session) Update() (int64, error) { if res, err := DBExec("UPDATE student_sessions SET id_student = ?, time = ? WHERE id_session = ?", s.IdStudent, s.Time, s.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { @@ -55,7 +54,7 @@ func (s *Session) Update() (int64, error) { } } -func (s *Session) Delete() (int64, error) { +func (s Session) Delete() (int64, error) { if res, err := DBExec("DELETE FROM student_sessions WHERE id_session = ?", s.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { diff --git a/libadlin/ssh.go b/libadlin/ssh.go index f699860..9e8f1be 100644 --- a/libadlin/ssh.go +++ b/libadlin/ssh.go @@ -16,14 +16,14 @@ type StudentKey struct { Time time.Time `json:"time"` } -func GetStudentKeys() (keys []*StudentKey, err error) { +func GetStudentKeys() (keys []StudentKey, err error) { if rows, errr := DBQuery("SELECT id_key, id_student, sshkey, time FROM student_keys"); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - k := &StudentKey{} + var k StudentKey if err = rows.Scan(&k.Id, &k.IdStudent, &k.Key, &k.Time); err != nil { return } @@ -37,14 +37,14 @@ func GetStudentKeys() (keys []*StudentKey, err error) { } } -func (s *Student) GetKeys() (keys []*StudentKey, err error) { +func (s Student) GetKeys() (keys []StudentKey, err error) { if rows, errr := DBQuery("SELECT id_key, id_student, sshkey, time FROM student_keys WHERE id_student = ?", s.Id); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - k := &StudentKey{} + var k StudentKey if err = rows.Scan(&k.Id, &k.IdStudent, &k.Key, &k.Time); err != nil { return } @@ -58,13 +58,12 @@ func (s *Student) GetKeys() (keys []*StudentKey, err error) { } } -func getStudentKey(id int) (k *StudentKey, err error) { - k = new(StudentKey) +func getStudentKey(id int) (k StudentKey, err error) { err = DBQueryRow("SELECT id_key, id_student, sshkey, time FROM student_keys WHERE id_key=?", id).Scan(&k.Id, &k.IdStudent, &k.Key, &k.Time) return } -func (s *Student) NewKey(key string) (k *StudentKey, err error) { +func (s Student) NewKey(key string) (k StudentKey, err error) { // Check key before importing it cmd := exec.Command("ssh-keygen", "-l", "-f", "-") cmd.Stdin = strings.NewReader(key) @@ -102,20 +101,20 @@ func (s *Student) NewKey(key string) (k *StudentKey, err error) { key = keyf[0] + " " + keyf[1] if res, err := DBExec("INSERT INTO student_keys (id_student, sshkey, time) VALUES (?, ?, ?)", s.Id, key, time.Now()); err != nil { - return nil, err + return StudentKey{}, err } else if kid, err := res.LastInsertId(); err != nil { - return nil, err + return StudentKey{}, err } else { s.UnlockNewChallenge(11, "") - return &StudentKey{kid, s.Id, key, time.Now()}, nil + return StudentKey{kid, s.Id, key, time.Now()}, nil } } -func (k *StudentKey) GetStudent() (*Student, error) { +func (k StudentKey) GetStudent() (Student, error) { return GetStudent(int(k.IdStudent)) } -func (k *StudentKey) Update() (int64, error) { +func (k StudentKey) Update() (int64, error) { if res, err := DBExec("UPDATE student_keys SET id_student = ?, sshkey = ?, time = ? WHERE id_key = ?", k.IdStudent, k.Key, k.Time, k.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { @@ -125,7 +124,7 @@ func (k *StudentKey) Update() (int64, error) { } } -func (k *StudentKey) Delete() (int64, error) { +func (k StudentKey) Delete() (int64, error) { if res, err := DBExec("DELETE FROM student_keys WHERE id_key = ?", k.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { diff --git a/libadlin/students.go b/libadlin/students.go index 9903cc0..c4790da 100644 --- a/libadlin/students.go +++ b/libadlin/students.go @@ -3,29 +3,26 @@ package adlin import ( "crypto/hmac" "crypto/sha512" - "fmt" "time" ) type Student struct { - Id int64 `json:"id"` - Login string `json:"login"` - Time *time.Time `json:"time"` - IP *string `json:"ip"` - MAC *string `json:"mac"` - AssociatedDomain *string `json:"associated_domain,omitempty"` - DelegatedDomain *string `json:"delegated_domain,omitempty"` + Id int64 `json:"id"` + Login string `json:"login"` + Time *time.Time `json:"time"` + IP *string `json:"ip"` + MAC *string `json:"mac"` } -func GetStudents() (students []*Student, err error) { - if rows, errr := DBQuery("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac, S.associatedDomain, S.delegatedDomain FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student GROUP BY id_student"); errr != nil { +func GetStudents() (students []Student, err error) { + if rows, errr := DBQuery("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student GROUP BY id_student"); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - s := &Student{} - if err = rows.Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC, &s.AssociatedDomain, &s.DelegatedDomain); err != nil { + var s Student + if err = rows.Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC); err != nil { return } students = append(students, s) @@ -38,15 +35,13 @@ func GetStudents() (students []*Student, err error) { } } -func GetStudent(id int) (s *Student, err error) { - s = new(Student) - err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac, S.associatedDomain, S.delegatedDomain FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE S.id_student=?", id).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC, &s.AssociatedDomain, &s.DelegatedDomain) +func GetStudent(id int) (s Student, err error) { + err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE S.id_student=?", id).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC) return } -func GetStudentByLogin(login string) (s *Student, err error) { - s = new(Student) - err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac, S.associatedDomain, S.delegatedDomain FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE login=?", login).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC, &s.AssociatedDomain, &s.DelegatedDomain) +func GetStudentByLogin(login string) (s Student, err error) { + err = DBQueryRow("SELECT S.id_student, S.login, MAX(L.time), L.ip, L.mac FROM students S INNER JOIN (SELECT a.id_student, a.time, a.ip, a.mac FROM student_login a INNER JOIN (SELECT id_student, MAX(time) AS time FROM student_login GROUP BY id_student) b ON a.id_student = b.id_student AND a.time = b.time) L ON S.id_student = L.id_student WHERE login=?", login).Scan(&s.Id, &s.Login, &s.Time, &s.IP, &s.MAC) return } @@ -56,23 +51,23 @@ func StudentExists(login string) bool { return err == nil && z == 1 } -func NewStudent(login string) (*Student, error) { +func NewStudent(login string) (Student, error) { t := time.Now() if res, err := DBExec("INSERT INTO students (login, time) VALUES (?, ?)", login, t); err != nil { - return nil, err + return Student{}, err } else if sid, err := res.LastInsertId(); err != nil { - return nil, err + return Student{}, err } else { - return &Student{sid, login, &t, nil, nil, nil, nil}, nil + return Student{sid, login, &t, nil, nil}, nil } } -func (s *Student) GetPKey() []byte { +func (s Student) GetPKey() []byte { return hmac.New(sha512.New512_224, []byte(SharedSecret)).Sum([]byte(s.Login)) } -func (s *Student) Update() (int64, error) { - if res, err := DBExec("UPDATE students SET login = ?, time = ?, associatedDomain = ?, delegatedDomain = ? WHERE id_student = ?", s.Login, s.Time, s.AssociatedDomain, s.DelegatedDomain, s.Id); err != nil { +func (s Student) Update() (int64, error) { + if res, err := DBExec("UPDATE students SET login = ?, time = ? WHERE id_student = ?", s.Login, s.Time, s.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err @@ -81,7 +76,7 @@ func (s *Student) Update() (int64, error) { } } -func (s *Student) Delete() (int64, error) { +func (s Student) Delete() (int64, error) { if res, err := DBExec("DELETE FROM students WHERE id_student = ?", s.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { @@ -105,20 +100,18 @@ type UnlockedChallenge struct { Id int64 `json:"id,omitempty"` IdStudent int64 `json:"id_student"` Challenge int `json:"challenge,omitempty"` - Time *time.Time `json:"time,omitempty"` + Time time.Time `json:"time"` Value interface{} `json:"value,omitempty"` - LastCheck *time.Time `json:"last_check,omitempty"` - Error string `json:"error,omitempty"` } -func (s *Student) GetStates() (ucs []*UnlockedChallenge, err error) { +func (s Student) GetStates() (ucs []UnlockedChallenge, err error) { if rows, errr := DBQuery("SELECT id_st, challenge, time FROM student_challenges WHERE id_student = ?", s.Id); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - u := &UnlockedChallenge{} + var u UnlockedChallenge u.IdStudent = s.Id if err = rows.Scan(&u.Id, &u.Challenge, &u.Time); err != nil { return @@ -133,36 +126,14 @@ func (s *Student) GetStates() (ucs []*UnlockedChallenge, err error) { } } -func (s *Student) GetChallengeErrors() (ucs []*ErroredChallenge, err error) { - if rows, errr := DBQuery("SELECT id_st, challenge, time, error FROM student_challenge_errors WHERE id_student = ?", s.Id); errr != nil { - return nil, errr - } else { - defer rows.Close() - - for rows.Next() { - u := &ErroredChallenge{} - u.IdStudent = s.Id - if err = rows.Scan(&u.Id, &u.Challenge, &u.Time, &u.Error); err != nil { - return - } - ucs = append(ucs, u) - } - if err = rows.Err(); err != nil { - return - } - - return - } -} - -func (s *Student) GetStatesByChallenge() (ucs []*UnlockedChallenge, err error) { +func (s Student) GetStatesByChallenge() (ucs []UnlockedChallenge, err error) { if rows, errr := DBQuery("SELECT id_st, challenge, MIN(time), value FROM student_challenges WHERE id_student = ? GROUP BY challenge, id_student", s.Id); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - u := &UnlockedChallenge{} + var u UnlockedChallenge u.IdStudent = s.Id if err = rows.Scan(&u.Id, &u.Challenge, &u.Time, &u.Value); err != nil { return @@ -177,57 +148,25 @@ func (s *Student) GetStatesByChallenge() (ucs []*UnlockedChallenge, err error) { } } -func (s *Student) UnlockChallenge(challenge int, value string) (uc *UnlockedChallenge, err error) { - if uc, err = s.UnlockNewChallenge(challenge, value); err != nil { - if uc, err = s.UpdateUnlockedChallenge(challenge, value); err != nil { - return - } - } - - s.RegisterChallengeError(challenge, fmt.Errorf("OK")) - - return -} - -func (s *Student) UnlockNewChallenge(challenge int, value string) (*UnlockedChallenge, error) { +func (s Student) UnlockNewChallenge(challenge int, value string) (UnlockedChallenge, error) { if res, err := DBExec("INSERT INTO student_challenges (id_student, challenge, time, value) VALUES (?, ?, ?, ?)", s.Id, challenge, time.Now(), value); err != nil { - return nil, err + return UnlockedChallenge{}, err } else if utid, err := res.LastInsertId(); err != nil { - return nil, err + return UnlockedChallenge{}, err } else { - now := time.Now() - return &UnlockedChallenge{utid, s.Id, challenge, &now, value, nil, ""}, err + return UnlockedChallenge{utid, s.Id, challenge, time.Now(), value}, err } } -func (s *Student) UpdateUnlockedChallenge(challenge int, value string) (*UnlockedChallenge, error) { +func (s Student) UpdateUnlockedChallenge(challenge int, value string) (UnlockedChallenge, error) { if _, err := DBExec("UPDATE student_challenges SET time = ?, value = ? WHERE id_student = ? AND challenge = ?", time.Now(), value, s.Id, challenge); err != nil { - return nil, err + return UnlockedChallenge{}, err } else { - now := time.Now() - return &UnlockedChallenge{0, s.Id, challenge, &now, value, nil, ""}, err + return UnlockedChallenge{0, s.Id, challenge, time.Now(), value}, err } } -type ErroredChallenge struct { - Id int64 `json:"id,omitempty"` - IdStudent int64 `json:"id_student"` - Challenge int `json:"challenge,omitempty"` - Time time.Time `json:"time"` - Error string `json:"error,omitempty"` -} - -func (s *Student) RegisterChallengeError(challenge int, err error) error { - if _, errr := DBExec("INSERT INTO student_challenge_errors (id_student, challenge, time, error) VALUES (?, ?, ?, ?)", s.Id, challenge, time.Now(), err.Error()); errr == nil { - return nil - } else if _, errr := DBExec("UPDATE student_challenge_errors SET time = ?, error = ? WHERE id_student = ? AND challenge = ?", time.Now(), err.Error(), s.Id, challenge); errr != nil { - return errr - } else { - return nil - } -} - -func (s *Student) RegisterAccess(ip, mac string) error { +func (s Student) RegisterAccess(ip, mac string) error { if res, err := DBExec("INSERT INTO student_login (id_student, ip, mac, time) VALUES (?, ?, ?, ?)", s.Id, ip, mac, time.Now()); err != nil { return err } else if _, err := res.LastInsertId(); err != nil { diff --git a/libadlin/tunnel.go b/libadlin/tunnel.go index c22a520..5a177b0 100644 --- a/libadlin/tunnel.go +++ b/libadlin/tunnel.go @@ -12,19 +12,10 @@ import ( "time" ) -const StdNetmask = 80 - func StudentIP(idstd int64) net.IP { return net.ParseIP(fmt.Sprintf("2a01:e0a:2b:2252:%x::", idstd)) } -func StudentNet(idstd int64) *net.IPNet { - return &net.IPNet{ - IP: StudentIP(idstd), - Mask: net.CIDRMask(StdNetmask, 128), - } -} - type WGDump struct { PubKey string PSK string @@ -37,32 +28,32 @@ type WGDump struct { } var ( - wgDumpCache_data map[string]*WGDump = nil + wgDumpCache_data map[string]WGDump = nil wgDumpCache_time time.Time wgDumpCache_mutex sync.RWMutex ) -func _readWgDump() (wgd map[string]*WGDump, err error) { +func _readWgDump() (wgd map[string]WGDump, err error) { out, errr := exec.Command("wg", "show", "wg-adlin", "dump").Output() if errr != nil { return nil, errr } - wgd = map[string]*WGDump{} + wgd = map[string]WGDump{} for _, line := range strings.Split(string(out), "\n") { cols := strings.Fields(line) if len(cols) != 8 { continue } - wgd[cols[0]] = &WGDump{cols[0], cols[1], cols[2], cols[3], cols[4], cols[5], cols[6], cols[7]} + wgd[cols[0]] = WGDump{cols[0], cols[1], cols[2], cols[3], cols[4], cols[5], cols[6], cols[7]} } return } -func readWgDump() (wgd map[string]*WGDump, err error) { +func readWgDump() (wgd map[string]WGDump, err error) { wgDumpCache_mutex.RLock() defer wgDumpCache_mutex.RUnlock() @@ -103,48 +94,38 @@ type TunnelToken struct { Dump *WGDump } -func (tt *TunnelToken) GetStudentIP() string { - if tt.SuffixIP == 0 { - return fmt.Sprintf("%s%x", StudentIP(tt.IdStudent).String(), 1) - } else { - return fmt.Sprintf("%s%x", StudentIP(tt.IdStudent).String(), tt.SuffixIP) - } -} - -func TokenFromText(token string) []byte { +func tokenFromText(token string) []byte { sha := sha512.Sum512([]byte(token)) return sha[:] } -func GetTunnelToken(token []byte) (t *TunnelToken, err error) { - t = new(TunnelToken) +func GetTunnelToken(token []byte) (t TunnelToken, err error) { err = DBQueryRow("SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE token=? ORDER BY time DESC", token).Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version) if err == nil && t.PubKey != nil { if wgd, errr := readWgDump(); errr == nil { if v, ok := wgd[base64.StdEncoding.EncodeToString(t.PubKey)]; ok { - t.Dump = v + t.Dump = &v } } } return } -func (student *Student) NewTunnelToken(suffixip int) (t *TunnelToken, err error) { +func (student Student) NewTunnelToken(suffixip int) (t TunnelToken, err error) { tok := make([]byte, 7) if _, err = rand.Read(tok); err != nil { return } - t = new(TunnelToken) - t.TokenText = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(base64.RawStdEncoding.EncodeToString(tok), "/", ".", -1), "+", "_", -1), "O", "<", -1), "l", "$", -1), "I", ">", -1) - t.token = TokenFromText(t.TokenText) + t.TokenText = strings.Replace(strings.Replace(strings.Replace(strings.Replace(strings.Replace(base64.RawStdEncoding.EncodeToString(tok), "/", ".", -1), "+", "_", -1), "O", "#", -1), "l", "$", -1), "I", ">", -1) + t.token = tokenFromText(t.TokenText) t.IdStudent = student.Id _, err = DBExec("INSERT INTO student_tunnel_tokens (token, token_text, id_student, time, suffixip, version) VALUES (?, ?, ?, ?, ?, 0)", t.token, t.TokenText, student.Id, time.Now(), suffixip) return } -func (student *Student) GetTunnelTokens() (ts []*TunnelToken, err error) { +func (student Student) GetTunnelTokens() (ts []TunnelToken, err error) { if rows, errr := DBQuery("SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE id_student = ? ORDER BY time DESC", student.Id); errr != nil { return nil, errr } else if wgd, errr := readWgDump(); errr != nil { @@ -153,13 +134,13 @@ func (student *Student) GetTunnelTokens() (ts []*TunnelToken, err error) { defer rows.Close() for rows.Next() { - t := &TunnelToken{} + var t TunnelToken if err = rows.Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version); err != nil { return } if t.PubKey != nil { if v, ok := wgd[base64.StdEncoding.EncodeToString(t.PubKey)]; ok { - t.Dump = v + t.Dump = &v } } ts = append(ts, t) @@ -172,7 +153,7 @@ func (student *Student) GetTunnelTokens() (ts []*TunnelToken, err error) { } } -func (student *Student) GetActivesTunnels() (ts []*TunnelToken, err error) { +func (student Student) GetActivesTunnels() (ts []TunnelToken, err error) { if rows, errr := DBQuery("SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE id_student = ? ORDER BY time DESC", student.Id); errr != nil { return nil, errr } else if wgd, errr := readWgDump(); errr != nil { @@ -181,13 +162,13 @@ func (student *Student) GetActivesTunnels() (ts []*TunnelToken, err error) { defer rows.Close() for rows.Next() { - t := &TunnelToken{} + var t TunnelToken if err = rows.Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version); err != nil { return } if t.PubKey != nil { if v, ok := wgd[base64.StdEncoding.EncodeToString(t.PubKey)]; ok { - t.Dump = v + t.Dump = &v ts = append(ts, t) } } @@ -200,13 +181,12 @@ func (student *Student) GetActivesTunnels() (ts []*TunnelToken, err error) { } } -func (student *Student) GetTunnelToken(token []byte) (t *TunnelToken, err error) { - t = new(TunnelToken) +func (student Student) GetTunnelToken(token []byte) (t TunnelToken, err error) { err = DBQueryRow("SELECT token, token_text, id_student, pubkey, time, suffixip, version FROM student_tunnel_tokens WHERE token = ? AND id_student = ? ORDER BY time DESC", token, student.Id).Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version) if err == nil && t.PubKey != nil { if wgd, errr := readWgDump(); errr == nil { if v, ok := wgd[base64.StdEncoding.EncodeToString(t.PubKey)]; ok { - t.Dump = v + t.Dump = &v } } } @@ -214,7 +194,7 @@ func (student *Student) GetTunnelToken(token []byte) (t *TunnelToken, err error) } func (t *TunnelToken) Update() (int64, error) { - newtoken := TokenFromText(t.TokenText) + newtoken := tokenFromText(t.TokenText) tm := time.Now() if res, err := DBExec("UPDATE student_tunnel_tokens SET token = ?, token_text = ?, id_student = ?, pubkey = ?, time = ?, suffixip = ?, version = ? WHERE token = ?", newtoken, t.TokenText, t.IdStudent, t.PubKey, tm, t.SuffixIP, t.Version, t.token); err != nil { @@ -228,24 +208,14 @@ func (t *TunnelToken) Update() (int64, error) { } } -func (t *TunnelToken) Delete() (int64, error) { - if res, err := DBExec("DELETE FROM student_tunnel_tokens WHERE token = ? AND id_student = ?", t.token, t.IdStudent); err != nil { - return 0, err - } else if nb, err := res.RowsAffected(); err != nil { - return 0, err - } else { - return nb, err - } -} - -func GetStudentsTunnels() (ts []*TunnelToken, err error) { +func GetStudentsTunnels() (ts []TunnelToken, err error) { if rows, errr := DBQuery("SELECT T.token, T.token_text, T.id_student, T.pubkey, T.time, T.suffixip, T.version FROM student_tunnel_tokens T INNER JOIN (SELECT B.id_student, MAX(B.time) AS time FROM student_tunnel_tokens B WHERE B.pubkey IS NOT NULL GROUP BY id_student) L ON T.id_student = L.id_student AND T.time = L.time"); errr != nil { return nil, errr } else { defer rows.Close() for rows.Next() { - t := &TunnelToken{} + var t TunnelToken if err = rows.Scan(&t.token, &t.TokenText, &t.IdStudent, &t.PubKey, &t.Time, &t.SuffixIP, &t.Version); err != nil { return } diff --git a/token-validator/auth.go b/token-validator/auth.go index 97be90b..f90fec9 100644 --- a/token-validator/auth.go +++ b/token-validator/auth.go @@ -27,7 +27,7 @@ func init() { router.POST("/api/auth/logout", apiRawHandler(logout)) } -func validateAuthToken(s *adlin.Student, _ httprouter.Params, _ []byte) (interface{}, error) { +func validateAuthToken(s adlin.Student, _ httprouter.Params, _ []byte) (interface{}, error) { return s, nil } @@ -50,7 +50,7 @@ type loginForm struct { } func completeAuth(w http.ResponseWriter, username string, session *adlin.Session) (err error) { - var std *adlin.Student + var std adlin.Student if !adlin.StudentExists(username) { if std, err = adlin.NewStudent(username); err != nil { return err @@ -60,7 +60,9 @@ func completeAuth(w http.ResponseWriter, username string, session *adlin.Session } if session == nil { - session, err = std.NewSession() + var s adlin.Session + s, err = std.NewSession() + session = &s } else { _, err = session.SetStudent(std) } diff --git a/token-validator/auth_oidc.go b/token-validator/auth_oidc.go index 590676a..9118aea 100644 --- a/token-validator/auth_oidc.go +++ b/token-validator/auth_oidc.go @@ -111,7 +111,7 @@ func OIDC_CRI_complete(w http.ResponseWriter, r *http.Request, ps httprouter.Par return } - if err := completeAuth(w, claims.Username, session); err != nil { + if err := completeAuth(w, claims.Username, &session); err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) return } diff --git a/token-validator/challenge.go b/token-validator/challenge.go index 51144f1..d21db5d 100644 --- a/token-validator/challenge.go +++ b/token-validator/challenge.go @@ -338,7 +338,7 @@ func receiveChallenge(r *http.Request, ps httprouter.Params, body []byte) (inter return nil, errors.New("This is not the expected token.") } - var std *adlin.Student + var std adlin.Student if stdid, err := strconv.Atoi(gt.Login); err == nil { if std, err = adlin.GetStudent(stdid); err != nil { @@ -388,7 +388,7 @@ func receiveToken(r *http.Request, body []byte, chid int) (interface{}, error) { if std, err := adlin.GetStudentByLogin(gt.Login); err != nil { return nil, err } else { - if err := challenges[chid-1].Check(std, >, chid); err != nil { + if err := challenges[chid-1].Check(&std, >, chid); err != nil { log.Printf("%s just try ch#%d: %s\n", std.Login, chid, err) return nil, err } diff --git a/token-validator/check.go b/token-validator/check.go index 722e54f..8e18faf 100644 --- a/token-validator/check.go +++ b/token-validator/check.go @@ -19,7 +19,7 @@ type checkGLUE struct { } func init() { - router.POST("/api/check/GLUE", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.POST("/api/check/GLUE", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var uc checkGLUE if err := json.Unmarshal(body, &uc); err != nil { return nil, err @@ -27,7 +27,7 @@ func init() { return true, check_GLUE_respond(student, uc.Domain, uc.IP) })) } -func check_GLUE_respond(student *adlin.Student, domain string, ip string) (err error) { +func check_GLUE_respond(student adlin.Student, domain string, ip string) (err error) { if !strings.HasPrefix(ip, adlin.StudentIP(student.Id).String()) { return fmt.Errorf("%q is not your IP range") } diff --git a/token-validator/domain.go b/token-validator/domain.go index 596f3bd..2497a72 100644 --- a/token-validator/domain.go +++ b/token-validator/domain.go @@ -22,151 +22,103 @@ var ( ) func init() { - router.GET("/api/adomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/adomains/", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return student.GetAssociatedDomains(), nil })) - router.POST("/api/adomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.POST("/api/adomains/", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { ue := &struct { Domain string `json:"domain"` A string `json:"a"` AAAA string `json:"aaaa"` - CNAME string `json:"cname,omitempty"` }{} if err := json.Unmarshal(body, &ue); err != nil { return nil, err } - if ue.Domain != "" && ue.A == "" && ue.AAAA == "" && ue.CNAME == "" { - student.AssociatedDomain = nil - - if _, err := student.Update(); err != nil { - return nil, err - } - - return true, nil - } else if ue.CNAME != "" { - cname := dns.Fqdn(ue.CNAME) - student.AssociatedDomain = &cname - - if _, err := student.Update(); err != nil { - return nil, err - } - - return true, nil - } else { - var aaaa net.IP - if ue != nil && len(ue.AAAA) > 0 { - aaaa = net.ParseIP(ue.AAAA) - } - - return true, AddAssociatedDomains(student, aaaa) + var aaaa net.IP + if ue != nil && len(ue.AAAA) > 0 { + aaaa = net.ParseIP(ue.AAAA) } + + return true, AddAssociatedDomains(student, aaaa) })) - router.GET("/api/adomains/:dn", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/adomains/:dn", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return GetAssociatedDomain(student, ps.ByName("dn")) })) - router.GET("/api/ddomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/ddomains/", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return []string{student.MyDelegatedDomain()}, nil })) - router.POST("/api/ddomains/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { - ue := &struct { - NS string `json:"ns"` - }{} - - if err := json.Unmarshal(body, &ue); err != nil { - return nil, err - } - - if ue.NS == "" { - student.DelegatedDomain = nil - - if _, err := student.Update(); err != nil { - return nil, err - } - - return true, nil - } else { - ns := dns.Fqdn(ue.NS) - student.DelegatedDomain = &ns - - if _, err := student.Update(); err != nil { - return nil, err - } - - return true, nil - } - })) - router.GET("/api/ddomains/:dn/", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/ddomains/:dn/", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return getRRDelegatedDomain(student, ps.ByName("dn"), "") })) - router.GET("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/ddomains/:dn/NS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return getRRDelegatedDomain(student, ps.ByName("dn"), "NS") })) - router.POST("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.POST("/api/ddomains/:dn/NS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, AddNSDelegatedDomain(student, ps.ByName("dn"), ue.TTL, strings.Join(ue.Values, " ")) })) - router.PATCH("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.PATCH("/api/ddomains/:dn/NS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, UpdateNSDelegatedDomain(student, ps.ByName("dn"), ue.TTL, ue.ValuesFrom, strings.Join(ue.Values, "")) })) - router.DELETE("/api/ddomains/:dn/NS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.DELETE("/api/ddomains/:dn/NS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, DeleteRRDelegatedDomain(student, ps.ByName("dn"), "NS", strings.Join(ue.Values, " ")) })) - router.GET("/api/ddomains/:dn/GLUE", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/ddomains/:dn/GLUE", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return getRRDelegatedDomain(student, ps.ByName("dn"), "AAAA") })) - router.POST("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.POST("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, AddGLUEDelegatedDomain(student, ps.ByName("dn"), ue.TTL, strings.Join(ue.Values, " ")) })) - router.PATCH("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.PATCH("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, UpdateGLUEDelegatedDomain(student, ps.ByName("dn"), ue.TTL, ue.ValuesFrom, strings.Join(ue.Values, " ")) })) - router.POST("/api/ddomains/:dn/GLUE", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.POST("/api/ddomains/:dn/GLUE", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, UpdateGLUEDelegatedDomain(student, ps.ByName("dn"), ue.TTL, ue.ValuesFrom, strings.Join(ue.Values, " ")) })) - router.DELETE("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.DELETE("/api/ddomains/:dn/AAAA", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, DeleteRRDelegatedDomain(student, ps.ByName("dn"), "AAAA", strings.Join(ue.Values, " ")) })) - router.GET("/api/ddomains/:dn/DS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/ddomains/:dn/DS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return getRRDelegatedDomain(student, ps.ByName("dn"), "DS") })) - router.POST("/api/ddomains/:dn/DS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.POST("/api/ddomains/:dn/DS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err } return true, AddDSDelegatedDomain(student, ps.ByName("dn"), ue.TTL, strings.Join(ue.Values, " ")) })) - router.DELETE("/api/ddomains/:dn/DS", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.DELETE("/api/ddomains/:dn/DS", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { var ue Entry if err := json.Unmarshal(body, &ue); err != nil { return nil, err @@ -223,7 +175,7 @@ func parseZoneRead(globalDomain string, domain string) (rr []Entry, err error) { return } -func GetAssociatedDomain(student *adlin.Student, dn string) (rrs []Entry, err error) { +func GetAssociatedDomain(student adlin.Student, dn string) (rrs []Entry, err error) { domains := student.GetAssociatedDomains() found := false for _, d := range domains { @@ -249,7 +201,7 @@ func GetAssociatedDomain(student *adlin.Student, dn string) (rrs []Entry, err er return } -func delAssociatedDomains(student *adlin.Student, dn string) (err error) { +func delAssociatedDomains(student adlin.Student, dn string) (err error) { var adomains []Entry adomains, err = GetAssociatedDomain(student, dn) if err != nil { @@ -286,15 +238,15 @@ func delAssociatedDomains(student *adlin.Student, dn string) (err error) { return } -func AddAssociatedDomains(student *adlin.Student, aaaa net.IP) (err error) { - err = delAssociatedDomains(student, student.DefaultAssociatedDomain()) +func AddAssociatedDomains(student adlin.Student, aaaa net.IP) (err error) { + err = delAssociatedDomains(student, student.MyAssociatedDomain()) if err != nil { return } if aaaa == nil { aaaa = net.ParseIP(adlin.StudentIP(student.Id).String() + "1") - } else if !adlin.StudentNet(student.Id).Contains(aaaa) { + } else if !strings.HasPrefix(aaaa.String(), adlin.StudentIP(student.Id).String()) { return errors.New("The associated IP has to be in your IP range.") } @@ -305,12 +257,12 @@ func AddAssociatedDomains(student *adlin.Student, aaaa net.IP) (err error) { m2.Question[0] = dns.Question{adlin.AssociatedDomainSuffix, dns.TypeSOA, dns.ClassINET} rrA := new(dns.A) - rrA.Hdr = dns.RR_Header{Name: student.DefaultAssociatedDomain(), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 3600} + rrA.Hdr = dns.RR_Header{Name: student.MyAssociatedDomain(), Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 3600} rrA.A = net.IPv4(82, 64, 31, 248) m2.Insert([]dns.RR{rrA}) rrAAAA := new(dns.AAAA) - rrAAAA.Hdr = dns.RR_Header{Name: student.DefaultAssociatedDomain(), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 3600} + rrAAAA.Hdr = dns.RR_Header{Name: student.MyAssociatedDomain(), Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 3600} rrAAAA.AAAA = aaaa m2.Insert([]dns.RR{rrAAAA}) @@ -322,7 +274,7 @@ func AddAssociatedDomains(student *adlin.Student, aaaa net.IP) (err error) { return } -func getRRDelegatedDomain(student *adlin.Student, dn string, rr string) (rrs []Entry, err error) { +func getRRDelegatedDomain(student adlin.Student, dn string, rr string) (rrs []Entry, err error) { domains := []string{student.MyDelegatedDomain()} found := false for _, d := range domains { @@ -348,7 +300,7 @@ func getRRDelegatedDomain(student *adlin.Student, dn string, rr string) (rrs []E return } -func AddNSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, ns string) (err error) { +func AddNSDelegatedDomain(student adlin.Student, dn string, ttl uint32, ns string) (err error) { for _, d := range []string{student.MyDelegatedDomain()} { m1 := new(dns.Msg) m1.Id = dns.Id() @@ -371,7 +323,7 @@ func AddNSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, ns stri return } -func UpdateNSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, oldns string, ns string) (err error) { +func UpdateNSDelegatedDomain(student adlin.Student, dn string, ttl uint32, oldns string, ns string) (err error) { for _, d := range []string{student.MyDelegatedDomain()} { m1 := new(dns.Msg) m1.Id = dns.Id() @@ -399,7 +351,7 @@ func UpdateNSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, oldn return } -func AddGLUEDelegatedDomain(student *adlin.Student, dn string, ttl uint32, aaaa string) (err error) { +func AddGLUEDelegatedDomain(student adlin.Student, dn string, ttl uint32, aaaa string) (err error) { domains := []string{student.MyDelegatedDomain()} found := false for _, d := range domains { @@ -435,7 +387,7 @@ func AddGLUEDelegatedDomain(student *adlin.Student, dn string, ttl uint32, aaaa return } -func UpdateGLUEDelegatedDomain(student *adlin.Student, dn string, ttl uint32, oldaaaa string, aaaa string) (err error) { +func UpdateGLUEDelegatedDomain(student adlin.Student, dn string, ttl uint32, oldaaaa string, aaaa string) (err error) { domains := []string{student.MyDelegatedDomain()} found := false for _, d := range domains { @@ -477,7 +429,7 @@ func UpdateGLUEDelegatedDomain(student *adlin.Student, dn string, ttl uint32, ol return } -func AddDSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, rdata string) (err error) { +func AddDSDelegatedDomain(student adlin.Student, dn string, ttl uint32, rdata string) (err error) { domains := []string{student.MyDelegatedDomain()} found := false for _, d := range domains { @@ -527,7 +479,7 @@ func AddDSDelegatedDomain(student *adlin.Student, dn string, ttl uint32, rdata s return } -func DeleteRRDelegatedDomain(student *adlin.Student, dn string, rr string, values ...string) (err error) { +func DeleteRRDelegatedDomain(student adlin.Student, dn string, rr string, values ...string) (err error) { domains := []string{student.MyDelegatedDomain()} found := false for _, d := range domains { diff --git a/token-validator/handler.go b/token-validator/handler.go index d40be85..c93c842 100644 --- a/token-validator/handler.go +++ b/token-validator/handler.go @@ -65,7 +65,7 @@ func rawHandler(f func(http.ResponseWriter, *http.Request, httprouter.Params, [] http.Error(w, fmt.Sprintf(`{"errmsg": %q}`, err), http.StatusUnauthorized) return } else { - student = std + student = &std } } @@ -158,7 +158,7 @@ func apiHandler(f DispatchFunction, access ...func(*adlin.Student, *http.Request return rawHandler(responseHandler(func(_ *http.Request, ps httprouter.Params, b []byte) (interface{}, error) { return f(ps, b) }), access...) } -func apiAuthHandler(f func(*adlin.Student, httprouter.Params, []byte) (interface{}, error), access ...func(*adlin.Student, *http.Request) error) func(http.ResponseWriter, *http.Request, httprouter.Params) { +func apiAuthHandler(f func(adlin.Student, httprouter.Params, []byte) (interface{}, error), access ...func(*adlin.Student, *http.Request) error) func(http.ResponseWriter, *http.Request, httprouter.Params) { return rawHandler(responseHandler(func(r *http.Request, ps httprouter.Params, b []byte) (interface{}, error) { if cookie, err := r.Cookie("auth"); err != nil { return nil, errors.New("Authorization required") @@ -176,7 +176,7 @@ func apiAuthHandler(f func(*adlin.Student, httprouter.Params, []byte) (interface }), access...) } -func studentHandler(f func(*adlin.Student, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { +func studentHandler(f func(adlin.Student, []byte) (interface{}, error)) func(httprouter.Params, []byte) (interface{}, error) { return func(ps httprouter.Params, body []byte) (interface{}, error) { if sid, err := strconv.Atoi(string(ps.ByName("sid"))); err != nil { if student, err := adlin.GetStudentByLogin(ps.ByName("sid")); err != nil { diff --git a/token-validator/htdocs/dashboard.html b/token-validator/htdocs/dashboard.html index 8783eb6..8815e14 100644 --- a/token-validator/htdocs/dashboard.html +++ b/token-validator/htdocs/dashboard.html @@ -24,7 +24,7 @@ height: calc(100vh / 5 - 0.3vh); margin-left: 0.2%; margin-bottom: 0.2vh; - width: calc(100vw / 13 - 0.26vw); + width: calc(100vw / 13 - 0.22vw); } .student-title { width: calc(2 * (100vw / 13 - 0.22vw) + 0.2vw); @@ -47,7 +47,7 @@ .login { max-width: 122px; } - .badge.badge-sm { + .badge { font-size: 59%; padding: .15em .35em; } @@ -72,12 +72,12 @@