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 @@

TP {{tutoid+1}}
- +

@@ -108,7 +108,7 @@ -
+
- +
@@ -126,7 +126,6 @@ - diff --git a/token-validator/htdocs/js/adlin-common.js b/token-validator/htdocs/js/adlin-common.js deleted file mode 100644 index a6e4f55..0000000 --- a/token-validator/htdocs/js/adlin-common.js +++ /dev/null @@ -1,28 +0,0 @@ -var tuto_progress = [ - { - 1: { title: "Is alive?", icon: "👋", label: "Token 1"}, - 2: { title: "DMZ reached", icon: "📚", label: "Token 2"}, - 3: { title: "HTTPS on + time", icon: "⏲", label: "Token 3"}, - 4: { title: "DNS ok", icon: "🍰", label: "Token 4"}, - 5: { title: "On Internet", icon: "🌎", label: "Token 5"}, - 6: { title: "Bonus caché", icon: "b", label: "Bonus 0"}, - 7: { title: "Bonus ICMP", icon: "🏓", label: "Bonus 1"}, - 8: { title: "Bonus disk", icon: "💽", label: "Bonus 2"}, - 9: { title: "Bonus email", icon: "📧", label: "Bonus 3"}, - 10: { title: "Wg tunnel", icon: "🚇", label: "Tunnel up"}, - 11: { title: "Uploaded SSH key", icon: "💊", label: "SSH"}, - }, - { - 100: { title: "HTTP on IP", icon: "0", label: "HTTP IP"}, - 101: { title: "HTTP on associated domain", icon: "1", label: "HTTP domain"}, - 102: { title: "HTTPS on associated domain", icon: "2", label: "HTTPS domain"}, - 103: { title: "DNS Delegation", icon: "3", label: "DNS"}, - 104: { title: "HTTP on delegated domain", icon: "4", label: "HTTP on NS"}, - 105: { title: "HTTPS on delegated domain", icon: "5", label: "HTTPS on NS"}, - 106: { title: "Matrix", icon: "6", label: "Matrix"}, - 107: { title: "DNSSEC (bonus)", icon: "7", label: "DNSSEC"}, - }, - { - 200: { title: "HTTP", label: "HTTP"}, - }, -]; diff --git a/token-validator/htdocs/js/adlin-dashboard.js b/token-validator/htdocs/js/adlin-dashboard.js index b0fd719..baee842 100644 --- a/token-validator/htdocs/js/adlin-dashboard.js +++ b/token-validator/htdocs/js/adlin-dashboard.js @@ -1,3 +1,32 @@ +var tuto_progress = [ + { + 1: { title: "Is alive?", label: "👋"}, + 2: { title: "DMZ reached", label: "📚"}, + 3: { title: "HTTPS on + time", label: "⏲"}, + 4: { title: "DNS ok", label: "🍰"}, + 5: { title: "On Internet", label: "🌎"}, + 6: { title: "Bonus caché", label: "b"}, + 7: { title: "Bonus ICMP", label: "🏓"}, + 8: { title: "Bonus disk", label: "💽"}, + 9: { title: "Bonus email", label: "📧"}, + 10: { title: "Wg tunnel", label: "🚇"}, + 11: { title: "Uploaded SSH key", label: "💊"}, + }, + { + 100: { title: "HTTP", label: "HTTP"}, + 101: { title: "HTTPS", label: "HTTPS"}, + 102: { title: "DNS", label: "DNS"}, + 103: { title: "Matrix", label: "Matrix"}, + }, + { + 200: { title: "HTTP", label: "HTTP"}, + 201: { title: "HTTPS", label: "HTTPS"}, + 202: { title: "DNS", label: "DNS"}, + 203: { title: "Matrix", label: "Matrix"}, + }, +]; + + angular.module("AdLinApp", ["ngResource", "ngSanitize"]) .factory("Student", function($resource) { return $resource("/api/students/:studentId", { studentId: '@id' }, { @@ -36,8 +65,7 @@ angular.module("AdLinApp") var refreshStd = function() { $scope.students = Student.query(); } - var myinterval = $interval(refreshStd, 1600000); - $scope.$on('$destroy', function () { $interval.cancel(myinterval); }); + $interval(refreshStd, 1600000); }) .controller("StudentsProgressionController", function($scope, $interval, Progression) { $scope.tuto_progress = tuto_progress; @@ -81,8 +109,7 @@ angular.module("AdLinApp") }) } refreshStd(); - var myinterval = $interval(refreshStd, 9750); - $scope.$on('$destroy', function () { $interval.cancel(myinterval); }); + $interval(refreshStd, 9750); }) .controller("StudentProgressionController", function($scope, $interval, $http, Student, StudentProgression) { $scope.tuto_progress = tuto_progress; @@ -106,8 +133,7 @@ angular.module("AdLinApp") } $scope.$watch("onestudent", function(onestudent) { refreshStd(); - var myinterval = $interval(refreshStd, 15000); - $scope.$on('$destroy', function () { $interval.cancel(myinterval); }); + $interval(refreshStd, 15000); }) }) .controller("PingController", function($scope, $interval, $http) { @@ -124,8 +150,7 @@ angular.module("AdLinApp") $scope.$watch("student", function(student) { student.$promise.then(function(std) { refreshPing(); - var myinterval = $interval(refreshPing, 15000); - $scope.$on('$destroy', function () { $interval.cancel(myinterval); }); + $interval(refreshPing, 15000); }) }) }) @@ -137,8 +162,7 @@ angular.module("AdLinApp") }); } refreshSSH(); - var myinterval = $interval(refreshSSH, 15500); - $scope.$on('$destroy', function () { $interval.cancel(myinterval); }); + $interval(refreshSSH, 15500); }) .controller("ProgressionController", function($scope, $interval, $http) { $scope.tuto_progress = tuto_progress; @@ -155,6 +179,5 @@ angular.module("AdLinApp") }); } refreshChal(); - var myinterval = $interval(refreshChal, 15750); - $scope.$on('$destroy', function () { $interval.cancel(myinterval); }); + $interval(refreshChal, 15750); }) diff --git a/token-validator/htdocs/js/adlin-main.js b/token-validator/htdocs/js/adlin-main.js index 05908d3..bdf72f9 100644 --- a/token-validator/htdocs/js/adlin-main.js +++ b/token-validator/htdocs/js/adlin-main.js @@ -44,17 +44,6 @@ angular.module("AdLinApp") } }) - .directive('integer', function() { - return { - require: 'ngModel', - link: function(scope, ele, attr, ctrl){ - ctrl.$parsers.unshift(function(viewValue){ - return parseInt(viewValue, 10); - }); - } - }; - }) - .component('toast', { bindings: { date: '=', @@ -111,8 +100,6 @@ angular.module("AdLinApp") }) .controller("ProgressionController", function($scope, $interval, $http) { - $scope.tuto_progress = tuto_progress; - $scope.mychallenges = {}; var refreshChal = function() { $http.get("api/students/" + $scope.student.id + "/progress").then(function(response) { @@ -163,10 +150,7 @@ angular.module("AdLinApp") }; $scope.updateTunnelInfo(); - var noUpdate = 0 - - $scope.updateTunnelsList = function() { - if (noUpdate == 0) + $scope.updateTunnelsList = function() { $http({ method: 'GET', url: "api/wg/", @@ -227,48 +211,11 @@ angular.module("AdLinApp") }); } - $scope.editTunnel = function(tunnel) { - tunnel.edit = true; - noUpdate++; - tunnel.newData = { - TokenText: tunnel.TokenText, - SuffixIP: tunnel.SuffixIP, - } - }; - - $scope.updateTunnel = function(tunnel) { - tunnel.pleaseWaitUpdate = true; - $http({ - method: 'PUT', - url: "api/wg/" + encodeURIComponent(tunnel.TokenText), - data: tunnel.newData - }).then(function(response) { - noUpdate--; - tunnel.SuffixIP = tunnel.newData.SuffixIP; - tunnel.TokenText = tunnel.newData.TokenText; - tunnel.edit = false; - tunnel.pleaseWaitUpdate = false; - $scope.updateTunnelsList(); - $scope.addToast({ - variant: "success", - title: "Maatma Tunnels", - msg: "Tunnel mise à jour avec succès !", - }); - }, function(response) { - tunnel.pleaseWaitUpdate = false; - $scope.addToast({ - variant: "danger", - title: "Maatma Tunnels", - msg: (response.data ? response.data.errmsg : "Impossible de contacter le serveur"), - }); - }); - } - $scope.dropTunnel = function(tunnel) { tunnel.pleaseWaitDrop = true; $http({ method: 'DELETE', - url: "api/wg/" + encodeURIComponent(tunnel.TokenText), + url: "api/wg/" + tunnel.TokenText, data: {} }).then(function(response) { $scope.updateTunnelsList(); @@ -383,123 +330,6 @@ angular.module("AdLinApp") }); } - $scope.useMyAssociationD = function() { - $scope.assoc = { - "domain": $scope.adomains[0].domain, - "cname": $scope.student.associated_domain?$scope.student.associated_domain:"", - } - $('#AssocMyDomainModal').modal('show'); - } - - $scope.newMyDomainAssociationD = function(assoc) { - $('#AssocMyDomainModal').modal('hide'); - $scope.pleaseWaitNewAssociation = true; - $http({ - method: 'POST', - url: "api/adomains/", - data: assoc, - }).then(function(response) { - $scope.updateAssociationD(); - $scope.checkLoginState(); - $scope.pleaseWaitNewAssociation = false; - $scope.addToast({ - variant: "success", - title: "Maatma Domain Names", - msg: "Votre domaine a bien été associé !", - }); - }, function(response) { - $scope.pleaseWaitNewAssociation = false; - $scope.addToast({ - variant: "danger", - title: "Maatma Domain Names", - msg: "Erreur durant l'association du domaine : " + response.data.errmsg, - }); - }); - } - - $scope.delMyDomainAssociationD = function(assoc) { - $('#AssocMyDomainModal').modal('hide'); - $scope.pleaseWaitNewAssociation = true; - assoc.cname = '' - $http({ - method: 'POST', - url: "api/adomains/", - data: assoc, - }).then(function(response) { - $scope.updateAssociationD(); - $scope.checkLoginState(); - $scope.pleaseWaitNewAssociation = false; - $scope.addToast({ - variant: "success", - title: "Maatma Domain Names", - msg: "Votre domaine n'est plus pris en compte. Vous devez utiliser l'association qui vous a été attribuée sous adlin20xx.p0m.fr.", - }); - }, function(response) { - $scope.pleaseWaitNewAssociation = false; - $scope.addToast({ - variant: "danger", - title: "Maatma Domain Names", - msg: "Erreur durant l'association du domaine : " + response.data.errmsg, - }); - }); - } - - $scope.useMyDelegationD = function() { - $scope.assoc = { - "ns": $scope.student.delegated_domain?$scope.student.delegated_domain:"", - } - $('#DelegateMyDomainModal').modal('show'); - } - - $scope.newMyDomainDelegationD = function(assoc) { - $('#DelegateMyDomainModal').modal('hide'); - $scope.pleaseWaitNewDelegation = true; - $http({ - method: 'POST', - url: "api/ddomains/", - data: assoc, - }).then(function(response) { - $scope.checkLoginState(); - $scope.pleaseWaitNewDelegation = false; - $scope.addToast({ - variant: "success", - title: "Maatma Domain Names", - msg: "Votre sous-domaine de délégation a bien été enregistré !", - }); - }, function(response) { - $scope.pleaseWaitNewDelegation = false; - $scope.addToast({ - variant: "danger", - title: "Maatma Domain Names", - msg: "Erreur durant la délégation du domaine : " + response.data.errmsg, - }); - }); - } - - $scope.delMyDomainDelegatedD = function() { - $scope.pleaseWaitNewDelegation = true; - $http({ - method: 'POST', - url: "api/ddomains/", - data: {}, - }).then(function(response) { - $scope.checkLoginState(); - $scope.pleaseWaitNewDelegation = false; - $scope.addToast({ - variant: "success", - title: "Maatma Domain Names", - msg: "Votre domaine n'est plus pris en compte. Vous devez utiliser la délégation qui vous a été attribuée sous srs.p0m.fr.", - }); - }, function(response) { - $scope.pleaseWaitNewDelegation = false; - $scope.addToast({ - variant: "danger", - title: "Maatma Domain Names", - msg: "Erreur durant la délégation du domaine : " + response.data.errmsg, - }); - }); - } - $scope.addNS = function(domain) { $scope.nsrr = { "domain": domain, diff --git a/token-validator/htdocs/maatma.html b/token-validator/htdocs/maatma.html index 67cc023..2128f2f 100644 --- a/token-validator/htdocs/maatma.html +++ b/token-validator/htdocs/maatma.html @@ -46,7 +46,6 @@ - diff --git a/token-validator/htdocs/views/domains.html b/token-validator/htdocs/views/domains.html index fe02e77..cd2161a 100644 --- a/token-validator/htdocs/views/domains.html +++ b/token-validator/htdocs/views/domains.html @@ -2,10 +2,7 @@ Noms de domaine -

- Association simple - ? -

+

Association simple

@@ -31,9 +28,6 @@ Demander une nouvelle association - @@ -41,10 +35,7 @@
-

- Délégation - ? -

+

Délégation

-
+
-

- {{ domain }} - -

+

{{ domain }}

@@ -80,7 +65,7 @@ - - - - + + + - - - - +
{{ val }} - + Not implemented yet @@ -195,31 +180,7 @@ -
-

- {{ student.delegated_domain }} - -

-

- Vous avez choisi d'utiliser votre propre domaine pour réaliser la délégation. -

-

- L'interface de maatma ne vous est plus utile, car pour réaliser la délégation, vous devez passer par l'interface de votre bureau d'enregistrement. -

-

- Pour rappel, voici les enregistrements à rajouter : -

-
-;; Delegation {{ student.delegated_domain }} to the given name server
-{{ student.delegated_domain }} 300 IN NS ns.{{ student.delegated_domain }}
 
-;; GLUE record to serve along with the previous record
-ns.{{ student.delegated_domain }} 300 IN AAAA [your NS ip]
-  
-
- - - -
- Token - ? - - Suffix - ? - - Dernière utilisation - ? - - Clef publique - ? - TokenDernière utilisationClef publique
- > - + > + {{ tunnel.TokenText }} - - {{ tunnel.SuffixIP }}Par défaut {{ tunnel.Time | date:"medium" }} (VM TP {{ tunnel.Version }}){{ tunnel.PubKey }}(none){{ tunnel.PubKey }}(none) - - - @@ -67,10 +42,7 @@
-

- Paramètres du tunnel - ? -

+

Paramètres du tunnel

  • Statut : {{ wginfo.status }}
  • Clef publique du serveur : {{ wginfo.srv_pubkey }}
  • @@ -79,11 +51,10 @@
  • Gateway/passerelle IPv6 : {{ wginfo.srv_gw6 }}
-
+

État de mon tunnel - 💻 - ? + 💻

  • Clef publique pair : {{ tunnel.Dump.PubKey }}
  • diff --git a/token-validator/ip.go b/token-validator/ip.go index 885cd0f..aca9a79 100644 --- a/token-validator/ip.go +++ b/token-validator/ip.go @@ -3,7 +3,6 @@ package main import ( "fmt" "net" - "strconv" "github.com/julienschmidt/httprouter" @@ -12,12 +11,12 @@ import ( func init() { router.GET("/api/ips", apiHandler(showIPs)) - router.GET("/api/students/:sid/ips", apiHandler(studentHandler(func(student *adlin.Student, body []byte) (interface{}, error) { + router.GET("/api/students/:sid/ips", apiHandler(studentHandler(func(student adlin.Student, body []byte) (interface{}, error) { return getStudentIPs(student), nil }))) } -func IPSuffix(s *adlin.Student, network net.IPNet) net.IP { +func IPSuffix(s adlin.Student, network net.IPNet) net.IP { ipshift := s.Id*4 + 10 myIP := network.IP @@ -55,32 +54,13 @@ func showIPs(_ httprouter.Params, body []byte) (interface{}, error) { return r, nil } -func GetStudentTunnelIPs(student *adlin.Student) (ips []string) { - if ts, err := student.GetActivesTunnels(); err != nil || len(ts) == 0 || ts[0].SuffixIP == 0 { - ips = append(ips, adlin.StudentIP(student.Id).String()+"1") - } else { - for _, t := range ts { - ips = append(ips, t.GetStudentIP()) - } - } - return -} - -func getStudentIPs(student *adlin.Student) (r map[string]string) { +func getStudentIPs(student adlin.Student) (r map[string]string) { r = make(map[string]string) r["vlan0"] = IPSuffix(student, net.IPNet{net.ParseIP("172.23.0.0"), net.CIDRMask(17, 32)}).String() r["wg0"] = IPSuffix(student, net.IPNet{net.ParseIP("172.17.0.0"), net.CIDRMask(16, 32)}).String() r["vlan7"] = IPSuffix(student, net.IPNet{net.ParseIP("172.23.142.0"), net.CIDRMask(23, 32)}).String() - - for d, ip := range GetStudentTunnelIPs(student) { - key := "wg" - if d > 0 { - key += strconv.Itoa(d) - } - r[key] = ip - } - + r["wg"] = adlin.StudentIP(student.Id).String() r["adn"] = student.MyAssociatedDomain() r["ddn"] = student.MyDelegatedDomain() diff --git a/token-validator/ping.go b/token-validator/ping.go index 37a6290..b6441c5 100644 --- a/token-validator/ping.go +++ b/token-validator/ping.go @@ -11,13 +11,13 @@ var PongSecret = "felixfixit" func init() { router.GET("/api/students/:sid/ping", apiHandler(studentHandler(lastPing))) - router.GET("/api/students/:sid/pong", apiHandler(studentHandler(func(student *adlin.Student, body []byte) (interface{}, error) { + router.GET("/api/students/:sid/pong", apiHandler(studentHandler(func(student adlin.Student, body []byte) (interface{}, error) { return student.LastPongs() }))) router.POST("/api/students/:sid/pong", apiHandler(studentHandler(stdPong), sslOnly)) } -func lastPing(student *adlin.Student, body []byte) (interface{}, error) { +func lastPing(student adlin.Student, body []byte) (interface{}, error) { if pongs, err := student.LastPongs(); err != nil { return nil, err } else if len(pongs) <= 0 { @@ -27,7 +27,7 @@ func lastPing(student *adlin.Student, body []byte) (interface{}, error) { } } -func stdPong(student *adlin.Student, body []byte) (interface{}, error) { +func stdPong(student adlin.Student, body []byte) (interface{}, error) { var gt givenToken if err := json.Unmarshal(body, >); err != nil { return nil, err diff --git a/token-validator/ssh.go b/token-validator/ssh.go index f810571..666db4c 100644 --- a/token-validator/ssh.go +++ b/token-validator/ssh.go @@ -47,7 +47,7 @@ func init() { }) } -func hasSSHKeys(student *adlin.Student, body []byte) (interface{}, error) { +func hasSSHKeys(student adlin.Student, body []byte) (interface{}, error) { if keys, err := student.GetKeys(); err != nil { return nil, err } else { @@ -141,7 +141,7 @@ func dumpAuthorizedKeysFile(w io.Writer) { } } -func dumpStdAuthorizedKeysFile(s *adlin.Student, w io.Writer) { +func dumpStdAuthorizedKeysFile(s adlin.Student, w io.Writer) { seen := map[string]interface{}{} if keys, _ := s.GetKeys(); keys != nil { diff --git a/token-validator/students.go b/token-validator/students.go index cee1e47..ac101fa 100644 --- a/token-validator/students.go +++ b/token-validator/students.go @@ -18,19 +18,19 @@ func init() { if stds, err := adlin.GetStudents(); err != nil { return nil, err } else { - ret := map[string]map[string]*adlin.UnlockedChallenge{} + ret := map[string]map[string]adlin.UnlockedChallenge{} for _, std := range stds { if sts, err := std.GetStates(); err == nil { - ret[std.Login] = map[string]*adlin.UnlockedChallenge{} + ret[std.Login] = map[string]adlin.UnlockedChallenge{} for _, s := range sts { ret[std.Login][fmt.Sprintf("%d", s.Challenge)] = s } if pongs, err := std.LastPongs(); err == nil && len(pongs) > 0 { - ret[std.Login]["ping"] = &adlin.UnlockedChallenge{ + ret[std.Login]["ping"] = adlin.UnlockedChallenge{ IdStudent: std.Id, - Time: &pongs[0].Date, + Time: pongs[0].Date, Value: pongs[0].State, } } else if err != nil { @@ -47,17 +47,17 @@ func init() { })) router.POST("/api/students/", remoteValidatorHandler(apiHandler(createStudent))) router.GET("/api/students/:sid/", apiHandler(studentHandler( - func(std *adlin.Student, _ []byte) (interface{}, error) { + func(std adlin.Student, _ []byte) (interface{}, error) { return std, nil }))) router.PUT("/api/students/:sid/", remoteValidatorHandler(apiHandler(studentHandler(updateStudent)))) router.DELETE("/api/students/:sid/", remoteValidatorHandler(apiHandler(studentHandler( - func(std *adlin.Student, _ []byte) (interface{}, error) { + func(std adlin.Student, _ []byte) (interface{}, error) { return std.Delete() })))) router.GET("/api/students/:sid/progress", apiHandler(studentHandler( - func(std *adlin.Student, _ []byte) (interface{}, error) { - ret := map[string]*adlin.UnlockedChallenge{} + func(std adlin.Student, _ []byte) (interface{}, error) { + ret := map[string]adlin.UnlockedChallenge{} if sts, err := std.GetStates(); err == nil { for _, s := range sts { @@ -65,20 +65,6 @@ func init() { } } - if cerrors, err := std.GetChallengeErrors(); err == nil { - for _, cerr := range cerrors { - if _, ok := ret[fmt.Sprintf("%d", cerr.Challenge)]; ok { - ret[fmt.Sprintf("%d", cerr.Challenge)].Error = cerr.Error - ret[fmt.Sprintf("%d", cerr.Challenge)].LastCheck = &cerr.Time - } else { - ret[fmt.Sprintf("%d", cerr.Challenge)] = &adlin.UnlockedChallenge{ - LastCheck: &cerr.Time, - Error: cerr.Error, - } - } - } - } - return ret, nil }))) } @@ -96,7 +82,7 @@ func createStudent(_ httprouter.Params, body []byte) (interface{}, error) { return nil, err } - var exist *adlin.Student + var exist adlin.Student if exist, err = adlin.GetStudentByLogin(strings.TrimSpace(std.Login)); err != nil { if exist, err = adlin.NewStudent(strings.TrimSpace(std.Login)); err != nil { return nil, err @@ -110,8 +96,8 @@ func createStudent(_ httprouter.Params, body []byte) (interface{}, error) { return exist, nil } -func updateStudent(current *adlin.Student, body []byte) (interface{}, error) { - new := &adlin.Student{} +func updateStudent(current adlin.Student, body []byte) (interface{}, error) { + var new adlin.Student if err := json.Unmarshal(body, &new); err != nil { return nil, err } diff --git a/token-validator/wg.go b/token-validator/wg.go index 195a3f7..544dd81 100644 --- a/token-validator/wg.go +++ b/token-validator/wg.go @@ -27,22 +27,20 @@ func init() { } }) router.GET("/api/wg/", apiAuthHandler(showWgTunnel)) - router.GET("/api/wginfo", apiAuthHandler(func(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { + router.GET("/api/wginfo", apiAuthHandler(func(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { return getTunnelInfo(student.Id), nil })) router.POST("/api/wg/", apiAuthHandler(genWgToken)) router.GET("/api/wg/:token", getWgTunnelInfo) router.POST("/api/wg/:token", getWgTunnelInfo) - router.PUT("/api/wg/:token", apiAuthHandler(updateWgTunnel)) - router.DELETE("/api/wg/:token", apiAuthHandler(deleteWgTunnel)) } -func showWgTunnel(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { +func showWgTunnel(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { // Get tunnels assigned to the student return student.GetTunnelTokens() } -func genWgToken(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { +func genWgToken(student adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { // Generate a token to access related wg info return student.NewTunnelToken(0) } @@ -63,7 +61,7 @@ func getTunnelInfo(student int64) TunnelInfo { SrvPubKey: srv_pubkey, SrvPort: 42912, CltIPv6: adlin.StudentIP(student), - CltRange: adlin.StdNetmask, + CltRange: 80, SrvGW6: "2a01:e0a:2b:2252::1", } } @@ -123,16 +121,11 @@ func getWgTunnelInfo(w http.ResponseWriter, r *http.Request, ps httprouter.Param return } - // 0 is considered default for suffix, apply default now - if token.SuffixIP <= 0 { - token.SuffixIP = 1 - } - syncWgConf() tinfo := getTunnelInfo(token.IdStudent) - var student *adlin.Student + var student adlin.Student student, err = adlin.GetStudent(int(token.IdStudent)) if err != nil { http.Error(w, fmt.Sprintf("{errmsg:%q}", err), http.StatusBadRequest) @@ -145,58 +138,11 @@ PublicKey = %s Endpoint = %s:%d AllowedIPs = ::/0 PersistentKeepalive = 5 -# MyIPv6=%s%x/%d +# MyIPv6=%s1/%d # MyNetwork=%s/%d # GWIPv6=%s # MyLogin=%s -`, base64.StdEncoding.EncodeToString(tinfo.SrvPubKey), "82.64.31.248", tinfo.SrvPort, tinfo.CltIPv6, token.SuffixIP, 64, tinfo.CltIPv6, tinfo.CltRange, tinfo.SrvGW6, student.Login))) -} - -func updateWgTunnel(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { - token, err := adlin.GetTunnelToken(adlin.TokenFromText(ps.ByName("token"))) - if err != nil { - return nil, err - } - - if token.IdStudent != student.Id { - return nil, fmt.Errorf("Unauthorized") - } - - var newToken adlin.TunnelToken - if err := json.Unmarshal(body, &newToken); err != nil { - return nil, err - } - - token.TokenText = newToken.TokenText - token.PubKey = newToken.PubKey - token.SuffixIP = newToken.SuffixIP - - if _, err = token.Update(); err != nil { - return nil, err - } - - syncWgConf() - - return true, err -} - -func deleteWgTunnel(student *adlin.Student, ps httprouter.Params, body []byte) (interface{}, error) { - token, err := adlin.GetTunnelToken(adlin.TokenFromText(ps.ByName("token"))) - if err != nil { - return nil, err - } - - if token.IdStudent != student.Id { - return nil, fmt.Errorf("Unauthorized") - } - - if _, err = token.Delete(); err != nil { - return nil, err - } - - syncWgConf() - - return true, err +`, base64.StdEncoding.EncodeToString(tinfo.SrvPubKey), "82.64.31.248", tinfo.SrvPort, tinfo.CltIPv6, 64, tinfo.CltIPv6, tinfo.CltRange, tinfo.SrvGW6, student.Login))) } func GenWGConfig(w io.Writer) error { diff --git a/tuto2.yml b/tuto2.yml index bcd1223..efb3ebf 100644 --- a/tuto2.yml +++ b/tuto2.yml @@ -1,9 +1,9 @@ kernel: - image: linuxkit/kernel:4.19.121 + image: linuxkit/kernel:4.19.104 cmdline: "console=tty0 console=ttyS0 root=/dev/sda1 root=/dev/sr0 adlin.format=/dev/sda quiet" init: - - nemunaire/adlin-tuto2:a68d5f224331628dc525edf383ec7429dfe001b0 + - nemunaire/adlin-tuto2:41e341472a4a1b27dcf61c7d364f1f0a5f76fbe7 files: - path: etc/hostname @@ -15,7 +15,7 @@ files: - path: etc/resolv.conf contents: | - nameserver 9.9.9.10 + nameserver 9.9.9.9 nameserver 1.1.1.1 uid: 0 gid: 0 @@ -154,14 +154,6 @@ files: /bin/ip -6 route del default /bin/ip -6 route add default via $(sed 's/^.*GWIPv6=//p;d' etc/wireguard/adlin.conf) pref high - # Download intermediate fixes - curl -s -f -H "X-ADLIN-time: $(stat -c %Y /boot)" https://adlin.nemunai.re/fix-vm2 | sh - - # Retrieve ssh keys - mkdir -p root/.ssh/ - [ -f root/.ssh/authorized_keys ] || /usr/sbin/chroot . /usr/bin/curl -s -f https://cri.epita.fr/$(sed 's/^.*MyLogin=//p;d' etc/wireguard/adlin.conf).keys > root/.ssh/authorized_keys - [ -f etc/ssh/ssh_host_rsa_key ] || /usr/sbin/chroot . ssh-keygen -A - # To the user exec /usr/sbin/chroot . "${INITP}" uid: 0 @@ -178,7 +170,7 @@ files: - path: etc/shadow contents: | - root:$6$dQXVLB.662ob0XJL$wRhh73Q.Z3mBRHhM0rSw96dE0bOFykfIXa2Z2ncu6WVSOpFLdv5J6Br9AHhalO4wwG3xgPqqhvCdEMdroR2r50:18336:0:99999:7::: + root:$6$QNuPvO59Xk4UO3le$3P0V2ef6dHlKgO1FHsKcPPgOvL.YeCOPFqfIVTtpYn5eEn3xkgGYeM1RMCQ9l/eTc6rRc.l.WeRe1iJVznVGj/:18336:0:99999:7::: daemon:*:18316:0:99999:7::: bin:*:18316:0:99999:7::: sys:*:18316:0:99999:7::: diff --git a/tutorial/ansible/ansible.md b/tutorial/ansible/ansible.md index be65bfb..924bafd 100644 --- a/tutorial/ansible/ansible.md +++ b/tutorial/ansible/ansible.md @@ -20,9 +20,7 @@ Ansible est une solution de gestion de configuration. Basé sur [YAML](http://www.yaml.org/spec/1.2/spec.html), sa principale particularité est de ne pas nécessité de daemon sur les machines qu'il va gérer : tout se fait exclusivement via SSH, à partir de la machine d'un administrateur, possédant -Ansible (ou bien d'un système de gestion de configuration tel qu'[Ansible -Tower](https://www.ansible.com/products/tower) ou -[AWX](https://github.com/ansible/awx)). +Ansible. Son installation est très simple, car les dépendances sont minimes et l'outil n'a pas besoin de base de données pour fonctionner : tout va se faire à partir @@ -50,7 +48,7 @@ système et des utilisateurs. Un deuxième playbook est à rendre : `login-x-TP2/vitrine.yml`, celui-ci doit permettre de déployer (en parallèle de tous les autres), une page vitrine typique d'une entreprise (cf. la 4e question de cours ;)). Cette page doit être -accessible depuis votre domaine . +accessible depuis votre domaine . Mon première commande @@ -87,7 +85,7 @@ Lancez ensuite la commande suivante :
    ``` -42sh$ ansible --inventory-file hosts all --module-name ping --user root +42sh$ ansible --inventory-file hosts all --module-name ping --user root --ask-pass 192.168.0.106 | SUCCESS => { "changed": false, "ping": "pong" @@ -99,10 +97,6 @@ Vous devriez avoir un retour similaire à celui-ci, indiquant simplement que la connexion a bien été effectuée et que le nécessaire est bien installé sur la machine distance. -Si votre clef SSH n'a pas été récupérée depuis le CRI, vous pouvez rajouter -l'option `--ask-pass`, afin de pouvoir indiquer le mot de passe de connexion au -compte, sinon vous obtiendrez une erreur plutôt incrompréhensible. - ### Confort @@ -287,7 +281,7 @@ pour davantage de détails et d'exemples. La configuration de votre serveur SSH laisse à désirer. Corriger les problèmes énoncés par ces deux articles : --  ; +-  ; - . Mettez en place un *handler* pour relancer votre serveur SSH en cas de diff --git a/tutorial/ansible/deploiement-svc.md b/tutorial/ansible/deploiement-svc.md index 953725c..b8295f0 100644 --- a/tutorial/ansible/deploiement-svc.md +++ b/tutorial/ansible/deploiement-svc.md @@ -9,7 +9,7 @@ gestionnaire de configuration. Après cet échauffement, vous devriez être prêt à créer un *playbook* dédié à l'installation d'un serveur [Matrix](https://matrix.org/) : -![Element](riot.png "Element : un des clients utilisable pour joindre son serveur Matrix") +![Riot](riot.png "Riot : un des clients utilisable pour joindre son serveur Matrix") Vous connaissez et utilisez sans doute Slack, un service de messagerie @@ -34,7 +34,7 @@ dédié lorsque c'est possible (pas de `root` !), droits d'accès et permissions des répertoires, etc. Profitez des [modules de base de -données](https://docs.ansible.com/ansible/2.9/modules/list_of_database_modules.html) +données](http://docs.ansible.com/ansible/latest/list_of_database_modules.html) pour l'initialiser correctement. Et bien entendu de l'ensemble des modules décrits dans la documentation standard ! @@ -58,7 +58,7 @@ de données. Le *dump* obtenu est à placer dans `/var/backups/`. ## Client de test Vous n'êtes pas tenu d'installer un client. Pour vos tests, vous pouvez -utiliser , en changeant l'adresse du serveur Matrix pour +utiliser , en changeant l'adresse du serveur Matrix pour votre sous-domaine dédié à Matrix (normalement ). (Conservez le serveur d'identité à ). @@ -68,7 +68,7 @@ votre sous-domaine dédié à Matrix (normalement ## Validation Pour valider l'installation de votre serveur, rejoignez le canal -`#adlin:nemunai.re` et envoyez un message « Ping ! » pour signaler votre -présence. +`#adlin:nemunai.re` et envoyez un message « Ping ! » à `@nemubot:nemunai.re` +qui s'occupera de valider ce pallier. Vous devriez également pouvoir tester entre-vous. diff --git a/tutorial/ansible/maatma.md b/tutorial/ansible/maatma.md index 1b4af3a..d9c3832 100644 --- a/tutorial/ansible/maatma.md +++ b/tutorial/ansible/maatma.md @@ -42,10 +42,9 @@ Tunnel IPv6 Au premier lancement de votre VM, la machine vous demandera d'indiquer un jeton afin de mettre en place le tunnel IPv6. -Afin d'en obtenir un, rendez-vous sur la [page -Tunnels](https://adlin.nemunai.re/maatma/tunnels) et créez un nouveau -tunnel. Un jeton de 10 caractères s'affichera alors, c'est celui que -vous devrez recopier dans le terminal (attention à la casse !). +Afin d'en obtenir un, rendez-vous sur la page Tunnels et créez un nouveau +tunnel. Un jeton de 10 caractères s'affichera alors, c'est celui que vous +devrez recopier dans le terminal (attention à la casse !). ### Test du tunnel diff --git a/tutorial/ansible/nameserver.md b/tutorial/ansible/nameserver.md index b8ee6ce..0547423 100644 --- a/tutorial/ansible/nameserver.md +++ b/tutorial/ansible/nameserver.md @@ -19,136 +19,3 @@ Voici les grandes étapes : * tester avec `dig @9.9.9.9 ANY login-x.srs.p0m.fr` que votre serveur est bien joignable. Un ouvrage de référence, qui répondra à l'intégralité de vos questions et manières d'utiliser votre serveur DNS se trouve à . - - -## Coller aux spécifications - -Pourquoi une telle complexité apparente pour déléguer une zone DNS ? - -Vous êtes sur le point d'obtenir le contrôle total d'un domaine : -`login-x.srs.p0m.fr.`. Cela signifie que vous allez pouvoir décider, -depuis votre propre serveur de noms (respectueux des -[standards](https://www.ietf.org/rfc/rfc1034.txt)), comment vous allez -répondre aux serveurs résolveurs des utilisateurs. - -Le protocole DNS étant décentralisé, mais basé sur une arborescence -unique, il est nécessaire que les serveurs faisant autorité sur une -zone (`fr.`, `srs.p0m.fr.`, ...) fournissent toutes les informations -nécessaire pour que cette délégation fonctionne. - -À cet instant, vous connaissez l'adresse IPv6 routable sur Internet de votre -serveur de noms (comme vous n'avez aujourd'hui qu'une seule machine, c'est -l'adresse de votre tunnel). Il va donc falloir indiquer à Internet que c'est -cette IP qu'il faut contacter, si l'on veut interroger le serveur faisant -autorité. - -Concrètement, vous allez devoir vous attribuer un sous-domaine pour votre -serveur de noms, car c'est grâce à un enregistrement `NS` figurant dans la zone -parente (pour vous, la zone parente c'est `srs.p0m.fr`) que la délégation va se -faire. - -Dans le cas basique, on va utiliser les serveurs de quelqu'un d'autre (d'un -hébergement spécialisé par exemple, ou celui de son bureau d'enregistrement -s'ils proposent ce service). Auquel cas, on fera figurer ce genre -d'informations : - -``` -42sh$ dig @e.ext.nic.fr. NS epita.fr. -;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 17590 -;; Flags: qr rd; QUERY: 1; ANSWER: 0; AUTHORITY: 3; ADDITIONAL: 0 - -;; QUESTION SECTION: -;; epita.fr. IN NS - -;; AUTHORITY SECTION: -epita.fr. 172800 IN NS tooty.ionis-it.com. -epita.fr. 172800 IN NS kazooie.ionis-it.com. -epita.fr. 172800 IN NS banjo.ionis-it.com. - -;; Received 100 B -;; Time 2042-12-04 13:42:23 CET -;; From 2a00:d78:0:102:193:176:144:22@53(UDP) in 13.9 ms -``` - -La commande est envoyée spécifiquement aux serveurs de l'AFNIC, faisant -autorité pour la zone `fr.`. Les serveurs de l'AFNIC nous indiquent en retour, -que `epita.fr.` est déléguée à Ionis, et qu'elle dispose de 3 serveurs faisant -autorité. - -Mais dans votre cas, vous hébergez vous-même votre propre serveur au sein de -votre zone, vous n'avez pas d'autre domaine à votre disposition. C'est -également le cas de Wikipédia : - -``` -42sh$ dig @d0.org.afilias-nst.org. NS wikipedia.org. -;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 47396 -;; Flags: qr rd; QUERY: 1; ANSWER: 0; AUTHORITY: 3; ADDITIONAL: 3 - -;; QUESTION SECTION: -;; wikipedia.org. IN NS - -;; AUTHORITY SECTION: -wikipedia.org. 86400 IN NS ns0.wikimedia.org. -wikipedia.org. 86400 IN NS ns2.wikimedia.org. -wikipedia.org. 86400 IN NS ns1.wikimedia.org. - -[...] -``` - -On voit ici que pour résoudre les sous-domaines de `wikipedia.org.`, il faut -demander à `nsX.wikimedia.org.`. Mais comment obtenir alors, l'adresse de ces -serveurs de noms, puisque l'on ne sait pas où les contacter ...! - -C'est là que les *GLUE records* entrent en jeu ! - -J'ai volontairement tronqué la sortie de la commande précédente, en entier, c'est : - -``` -42sh$ dig @d0.org.afilias-nst.org. NS wikipedia.org. -;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 47396 -;; Flags: qr rd; QUERY: 1; ANSWER: 0; AUTHORITY: 3; ADDITIONAL: 3 - -;; QUESTION SECTION: -;; wikipedia.org. IN NS - -;; AUTHORITY SECTION: -wikipedia.org. 86400 IN NS ns0.wikimedia.org. -wikipedia.org. 86400 IN NS ns2.wikimedia.org. -wikipedia.org. 86400 IN NS ns1.wikimedia.org. - -;; ADDITIONAL SECTION: -ns0.wikimedia.org. 86400 IN A 208.80.154.238 -ns1.wikimedia.org. 86400 IN A 208.80.153.231 -ns2.wikimedia.org. 86400 IN A 91.198.174.239 - -;; Received 143 B -;; Time 2042-12-04 13:42:23 CET -;; From 2001:500:f::1@53(UDP) in 15.2 ms -``` - -Afin d'éviter de tourner en rond sans jamais avoir réponse à notre question, en -même temps que de nous répondre sur qui sont les serveurs faisant autorité pour -la zone `wikipedia.org.`, les serveurs gérant la zone `org.` indiquent -également à quelle adresse ont peut les contacter. - -Ce sont les administrateurs de la zone `wikipedia.org.` qui ont indiqué à -`org.` quels étaient leurs serveurs de noms. Et ils ont également donné des -*GLUE records*, pour permettre à la magie d'opérer. - -À vous maintenant de créer votre zone, en envoyant sur Maatma, le nom de -domaine votre serveur de noms, ainsi que le *GLUE record* qui lui correspond. - - -## DNSSEC (bonus) - -En bonus, vous devriez sécuriser les réponses envoyées par votre serveur DNS. - -Pour ce faire, et toujours parce que l'on se trouve dans le cadre d'une -structure arborescente, les clefs publiques permettant de valider les -enregistrements d'un domaine en particulier, sont publiées dans la zone -parente. C'est pourquoi, vous disposez sur Maatma, d'une interface vous -permettant d'indiquer vos clefs publiques. - -De nombreux articles sont disponibles sur Internet pour vous permettre de -configurer DNSSEC en fonction du serveur autoritaire que vous aurez choisi. À -vous de jouer ! diff --git a/tutorial/ansible/setup.md b/tutorial/ansible/setup.md index 44dd2bb..8fccf49 100644 --- a/tutorial/ansible/setup.md +++ b/tutorial/ansible/setup.md @@ -33,7 +33,7 @@ L'image d'installation ---------------------- Vous pouvez télécharger l'ISO du TP depuis -. +. Cette image contient un système Debian minimaliste, en partie préinstallé afin de vous permettre de commencer à travailler sans plus attendre ! @@ -261,8 +261,8 @@ machine, afin qu'elle ne teste que le lecteur de CD virtuel. Connexion --------- -Si la machine ne se connecte pas au réseau toute seule, vous allez devoir -l'aider en reproduisant les étapes que nous avons apprises au TP précédent. +La machine ne se connecte pas au réseau toute seule, vous allez devoir l'aider +en reproduisant les étapes que nous avons apprises au TP précédent. ### Requête DHCP @@ -295,7 +295,7 @@ pouvoir émettre un paquet sur le réseau. ``` 42sh$ ip link 1: enp3s0: mtu 1500 qdisc pfifo_fast state DOWN mode DEFAULT group default qlen 1000 - ^^^^^^^^^^ + ^^^^^^^^^^ ```
    diff --git a/tutorial/ansible/tutorial.md b/tutorial/ansible/tutorial.md index 48b0bcb..d471639 100644 --- a/tutorial/ansible/tutorial.md +++ b/tutorial/ansible/tutorial.md @@ -3,18 +3,18 @@ title: Administration Linux avancée -- TP n^o^ 2 subtitle: "Maatma : l'hébergeur DIY" author: Pierre-Olivier *nemunaire* [Mercier]{.smallcaps} institute: EPITA -date: Jeudi 4 mars 2021 +date: Lundi 16 mars 2020 abstract: | Durant ce deuxième TP, nous allons apprendre à déployer des services sur un serveur, de manière industrielle ! \vspace{1em} - La partie 5 de ce TP est un projet à rendre à au plus tard - le **jeudi 18 mars 2021 à 12 h 42**. Consultez la dernière + La partie 4 de ce TP est un projet à rendre à au plus tard + le **lundi 30 mars 2020 à 00 h 42 du matin**. Consultez la dernière section de chaque partie pour plus d'information sur les éléments à rendre. Et n'oubliez pas de répondre aux [questions de - cours](https://adlin.nemunai.re/quiz/9). + cours](https://adlin.nemunai.re/quiz/2). En tant que personnes sensibilisées à la sécurité des échanges électroniques, vous devrez m'envoyer vos rendus signés avec votre clef PGP. Pensez à diff --git a/tutorial/ansible/vitrine.md b/tutorial/ansible/vitrine.md index 080fb9a..833cbc3 100644 --- a/tutorial/ansible/vitrine.md +++ b/tutorial/ansible/vitrine.md @@ -20,7 +20,7 @@ reporter dans un fichiers au chapitre suivant ! Ma première vitrine ------------------- -Sur le domaine `login-x.adlin2022.p0m.fr`, déployez une vitrine d'entreprise +Sur le domaine `login_x.adlin2021.p0m.fr`, déployez une vitrine d'entreprise basique (pas besoin d'un Wordpress, un simple lot de pages HTML fera l'affaire). Vous aurez pour cela besoin d'un serveur web, dont le choix est laissé à votre @@ -29,13 +29,11 @@ discrétion. Vous pouvez utiliser les services de [Let's Encrypt](https://letsencrypt.org/) pour obtenir un certificat TLS. Compte tenu des limitations imposées, vous ne pourrez pas tous en créer un aujourd'hui, mais n'hésitez pas à retenter un peu -plus tard dans la semaine. Vous pouvez également obtenir vos certificats depuis -de nombreux autres services gratuits similaire : -[ZeroSSL](https://zerossl.com/), [buypass](https://www.buypass.com/), ... +plus tard dans la semaine. -D'ailleurs, si vous disposez de votre propre nom de domaine et que vous -souhaitez l'utiliser pour ce TP, vous pouvez suivre les instructions dans -l'interface de Maatma pour pouvoir l'utiliser. +*D'ailleurs, si vous disposez de votre propre nom de domaine et que vous +souhaitez l'utiliser pour ce TP, n'hésitez pas à me solliciter pour que je +mette en place les redirections adéquates.* Une fois votre serveur web configuré et votre vitrine installée, accédez à diff --git a/tutorial/ansible/what.md b/tutorial/ansible/what.md index 18dd802..58ee80a 100644 --- a/tutorial/ansible/what.md +++ b/tutorial/ansible/what.md @@ -7,7 +7,7 @@ Accéder à la machine virtuelle ------------------------------ Une fois la machine virtuelle démarrée, vous pouvez vous y connecter en `root` -avec le mot de passe `adlin2022`. +avec le mot de passe `adlin2021`. Vous pouvez également démarrer en mode *single user*, mais comme votre disque n'est sans doute pas encore utilisable à ce stade, vous ne pourrez pas changer @@ -30,13 +30,6 @@ local (sans passer par un NAT), n'oubliez pas de modifier le mot de passe `root` pour éviter que n'importe qui sur le réseau local (et ayant accès à ce TP), ne rentre sur votre machine. -Afin de vous faciliter la configuration de la machine par la suite, vos clefs -SSH publiques, [déclarées au -CRI](https://cri.epita.fr/users/nemunaire/ssh-keys/), sont automatiquement -ajoutées à l'utilisateur `root`. Rendez-vous dans l'interface du CRI pour les -mettre à jour si besoin. Notez qu'elles ne sont retéléchargées que si le -fichier `authorized_keys` n'existe pas. - ### Création d'un utilisateur