diff --git a/admin/api/certificate.go b/admin/api/certificate.go index f6762676..bdf56454 100644 --- a/admin/api/certificate.go +++ b/admin/api/certificate.go @@ -6,10 +6,12 @@ import ( "errors" "fmt" "io/ioutil" + "log" "math/big" "os" "path" "time" + "strconv" "srs.epita.fr/fic-server/admin/pki" "srs.epita.fr/fic-server/libfic" @@ -26,7 +28,21 @@ func init() { })) router.GET("/api/teams/:tid/certificates", apiHandler(teamHandler( - func(team fic.Team, _ []byte) (interface{}, error) { return fic.GetTeamCertificates(team) }))) + func(team fic.Team, _ []byte) (interface{}, error) { + if serials, err := pki.GetTeamSerials(TeamsDir, team.Id); err != nil { + return nil, err + } else { + var certs []fic.Certificate + for _, serial := range serials { + if cert, err := fic.GetCertificate(serial); err == nil { + certs = append(certs, cert) + } else { + log.Println("Unable to get back certificate, whereas an association exists on disk: ", err) + } + } + return certs, nil + } + }))) router.GET("/api/certs/", apiHandler(getCertificates)) router.POST("/api/certs/", apiHandler(generateClientCert)) @@ -128,7 +144,7 @@ func generateClientCert(_ httprouter.Params, _ []byte) (interface{}, error) { type CertExported struct { Id string `json:"id"` Creation time.Time `json:"creation"` - IdTeam *int64 `json:"id_team"` + IdTeam *uint64 `json:"id_team"` Revoked *time.Time `json:"revoked"` } @@ -137,8 +153,17 @@ func getCertificates(_ httprouter.Params, _ []byte) (interface{}, error) { return nil, err } else { ret := make([]CertExported, 0) - for _, c := range certificates { - ret = append(ret, CertExported{fmt.Sprintf("%d", c.Id), c.Creation, c.IdTeam, c.Revoked}) + for _, cert := range certificates { + dstLinkPath := path.Join(TeamsDir, pki.GetCertificateAssociation(cert.Id)) + + var idTeam *uint64 = nil + if lnk, err := os.Readlink(dstLinkPath); err == nil { + if tid, err := strconv.ParseUint(lnk, 10, 64); err == nil { + idTeam = &tid + } + } + + ret = append(ret, CertExported{fmt.Sprintf("%d", cert.Id), cert.Creation, idTeam, cert.Revoked}) } return ret, nil } @@ -154,15 +179,7 @@ func updateCertificateAssociation(cert fic.Certificate, body []byte) (interface{ return nil, err } - // TODO: This should be read from file system, not in DB: - // the relation is made through a symlink, so if it exists, it is suffisant to read the relation - // moreover, backend doesn't update the DB at registration, it only creates a symlink - cert.IdTeam = uc.Team - - var serial big.Int - serial.SetUint64(cert.Id) - - dstLinkPath := path.Join(TeamsDir, fmt.Sprintf("_AUTH_ID_%0X", serial.Bytes())) + dstLinkPath := path.Join(TeamsDir, pki.GetCertificateAssociation(cert.Id)) if uc.Team != nil { srcLinkPath := fmt.Sprintf("%d", *uc.Team) @@ -173,9 +190,5 @@ func updateCertificateAssociation(cert fic.Certificate, body []byte) (interface{ os.Remove(dstLinkPath) } - if _, err := cert.Update(); err != nil { - return nil, err - } else { - return cert, err - } + return cert, nil } diff --git a/admin/pki/team.go b/admin/pki/team.go new file mode 100644 index 00000000..8ac78494 --- /dev/null +++ b/admin/pki/team.go @@ -0,0 +1,46 @@ +package pki + +import ( + "fmt" + "io/ioutil" + "os" + "path" + "strconv" +) + +func GetCertificateAssociation(serial uint64) string { + return fmt.Sprintf("_AUTH_ID_%0X", serial) +} + +func GetAssociations(dirname string) (assocs []string, err error) { + if ds, errr := ioutil.ReadDir(dirname); err != nil { + return nil, errr + } else { + for _, d := range ds { + if d.Mode() & os.ModeSymlink == os.ModeSymlink { + assocs = append(assocs, d.Name()) + } + } + return + } +} + +func GetTeamSerials(dirname string, id_team int64) (serials []uint64, err error) { + // As futher comparaisons will be made with strings, convert it only one time + str_tid := fmt.Sprintf("%d", id_team) + + var assocs []string + if assocs, err = GetAssociations(dirname); err != nil { + return + } else { + for _, assoc := range assocs { + var tid string + if tid, err = os.Readlink(path.Join(dirname, assoc)); err == nil && tid == str_tid { + if serial, err := strconv.ParseUint(assoc[9:], 16, 64); err == nil { + serials = append(serials, serial) + } + } + } + } + return +} diff --git a/libfic/certificate.go b/libfic/certificate.go index be207940..a1a0b06f 100644 --- a/libfic/certificate.go +++ b/libfic/certificate.go @@ -20,20 +20,19 @@ type Certificate struct { Id uint64 `json:"id,string"` Creation time.Time `json:"creation"` Password string `json:"password"` - IdTeam *int64 `json:"id_team"` Revoked *time.Time `json:"revoked"` } // GetCertificates returns the list of all generated certificates. func GetCertificates() (certificates []Certificate, err error) { var rows *sql.Rows - if rows, err = DBQuery("SELECT id_cert, creation, password, id_team, revoked FROM certificates ORDER BY creation"); err == nil { + if rows, err = DBQuery("SELECT id_cert, creation, password, revoked FROM certificates ORDER BY creation"); err == nil { defer rows.Close() certificates = make([]Certificate, 0) for rows.Next() { var c Certificate - if err = rows.Scan(&c.Id, &c.Creation, &c.Password, &c.IdTeam, &c.Revoked); err != nil { + if err = rows.Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked); err != nil { return } certificates = append(certificates, c) @@ -44,28 +43,9 @@ func GetCertificates() (certificates []Certificate, err error) { } -// GetTeamCertificates returns all certificates generated for a given Team. -func GetTeamCertificates(team Team) (certificates []Certificate, err error) { - var rows *sql.Rows - if rows, err = DBQuery("SELECT id_cert, creation, password, id_team, revoked FROM certificates WHERE id_team = ? ORDER BY creation", team.Id); err == nil { - defer rows.Close() - - certificates = make([]Certificate, 0) - for rows.Next() { - var c Certificate - if err = rows.Scan(&c.Id, &c.Creation, &c.Password, &c.IdTeam, &c.Revoked); err != nil { - return - } - certificates = append(certificates, c) - } - err = rows.Err() - } - return -} - // GetCertificate retrieves a certificate from its serial number. func GetCertificate(serial uint64) (c Certificate, err error) { - err = DBQueryRow("SELECT id_cert, creation, password, id_team, revoked FROM certificates WHERE id_cert = ?", serial).Scan(&c.Id, &c.Creation, &c.Password, &c.IdTeam, &c.Revoked) + err = DBQueryRow("SELECT id_cert, creation, password, revoked FROM certificates WHERE id_cert = ?", serial).Scan(&c.Id, &c.Creation, &c.Password, &c.Revoked) return } @@ -87,13 +67,13 @@ func RegisterCertificate(serial uint64, password string) (Certificate, error) { if _, err := DBExec("INSERT INTO certificates (id_cert, creation, password) VALUES (?, ?, ?)", serial, now, password); err != nil { return Certificate{}, err } else { - return Certificate{serial, now, password, nil, nil}, nil + return Certificate{serial, now, password, nil}, nil } } // Update applies modifications back to the database. func (c Certificate) Update() (int64, error) { - if res, err := DBExec("UPDATE certificates SET creation = ?, password = ?, id_team = ?, revoked = ? WHERE id_cert = ?", c.Creation, c.Password, c.IdTeam, c.Revoked, c.Id); err != nil { + if res, err := DBExec("UPDATE certificates SET creation = ?, password = ?, revoked = ? WHERE id_cert = ?", c.Creation, c.Password, c.Revoked, c.Id); err != nil { return 0, err } else if nb, err := res.RowsAffected(); err != nil { return 0, err diff --git a/libfic/db.go b/libfic/db.go index e55b56d5..59ace81b 100644 --- a/libfic/db.go +++ b/libfic/db.go @@ -91,9 +91,7 @@ CREATE TABLE IF NOT EXISTS certificates( id_cert BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, creation TIMESTAMP NOT NULL, password VARCHAR(255) NOT NULL, - id_team INTEGER NULL, - revoked TIMESTAMP NULL, - FOREIGN KEY(id_team) REFERENCES teams(id_team) + revoked TIMESTAMP NULL ) DEFAULT CHARACTER SET = utf8 COLLATE = utf8_bin; `); err != nil { return err