Skip to content

Commit

Permalink
track team for instance
Browse files Browse the repository at this point in the history
  • Loading branch information
argonaut0 committed Sep 3, 2023
1 parent 4552280 commit 3bc0d8f
Show file tree
Hide file tree
Showing 7 changed files with 29 additions and 26 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
out
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# ubcctf/instanced

Manages challenge instances on-demand.

`instanced` runs in the cluster and exposes an HTTP API which is used to request instances.

- GET `/instances` - get list of active instances
- POST `/instances?chal=$CHALLNAME&team=$ID` - provision an instance for specific challenge and team
- DELETE `/instances?id=$ID` - delete challenge with id

Authenticate with `Bearer token`
14 changes: 8 additions & 6 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import (
_ "modernc.org/sqlite"
)

// InstanceRecord is a record used to keep track of an active instance
type InstanceRecord struct {
Id int64 `json:"id"`
Expiry time.Time `json:"expiry"`
Challenge string `json:"challenge"`
TeamID string `json:"team"`
}

func (in *Instancer) InitDB(file string) error {
Expand All @@ -20,7 +22,7 @@ func (in *Instancer) InitDB(file string) error {
return err
}
in.db = db
_, err = db.Exec("CREATE TABLE IF NOT EXISTS instances(id INTEGER PRIMARY KEY, challenge TEXT, expiry INTEGER);")
_, err = db.Exec("CREATE TABLE IF NOT EXISTS instances(id INTEGER PRIMARY KEY, challenge TEXT, team TEXT, expiry INTEGER);")
if err != nil {
return err
}
Expand All @@ -37,19 +39,19 @@ func (in *Instancer) InitDB(file string) error {
return nil
}

func (in *Instancer) InsertInstanceRecord(ttl time.Duration, challenge string) (InstanceRecord, error) {
func (in *Instancer) InsertInstanceRecord(ttl time.Duration, team string, challenge string) (InstanceRecord, error) {
if in.db == nil {
return InstanceRecord{}, errors.New("db not initialized")
}
expiry := time.Now().Add(ttl)

stmt, err := in.db.Prepare("INSERT INTO instances(challenge, expiry) values(?, ?)")
stmt, err := in.db.Prepare("INSERT INTO instances(challenge, team, expiry) values(?, ?, ?)")
if err != nil {
return InstanceRecord{}, err
}
defer stmt.Close()

res, err := stmt.Exec(challenge, expiry.Unix())
res, err := stmt.Exec(challenge, team, expiry.Unix())
if err != nil {
return InstanceRecord{}, err
}
Expand Down Expand Up @@ -88,7 +90,7 @@ func (in *Instancer) ReadInstanceRecords() ([]InstanceRecord, error) {
if in.db == nil {
return nil, errors.New("db not initialized")
}
rows, err := in.db.Query("SELECT id, challenge, expiry FROM instances")
rows, err := in.db.Query("SELECT id, challenge, team, expiry FROM instances")
if err != nil {
return nil, err
}
Expand All @@ -97,7 +99,7 @@ func (in *Instancer) ReadInstanceRecords() ([]InstanceRecord, error) {
for rows.Next() {
record := InstanceRecord{}
var t int64
err = rows.Scan(&record.Id, &record.Challenge, &t)
err = rows.Scan(&record.Id, &record.Challenge, &record.TeamID, &t)
if err != nil {
return records, err
}
Expand Down
4 changes: 2 additions & 2 deletions instancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ func (in *Instancer) DestroyInstance(rec InstanceRecord) error {
return nil
}

func (in *Instancer) CreateInstance(challenge string) (InstanceRecord, error) {
func (in *Instancer) CreateInstance(challenge, team string) (InstanceRecord, error) {
log := in.log.With().Str("component", "instanced").Logger()

chal, ok := in.challengeObjs[challenge]
Expand All @@ -141,7 +141,7 @@ func (in *Instancer) CreateInstance(challenge string) (InstanceRecord, error) {
ttl = 10 * time.Minute
}

rec, err := in.InsertInstanceRecord(ttl, challenge)
rec, err := in.InsertInstanceRecord(ttl, team, challenge)
if err != nil {
log.Error().Err(err).Msg("could not create instance record")
} else {
Expand Down
2 changes: 1 addition & 1 deletion main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ spec:
func ExampleInsertInstanceRecord() {
in := Instancer{}
in.InitDB("./tmp/test.db")
in.InsertInstanceRecord(time.Hour, "test_challenge")
in.InsertInstanceRecord(time.Hour, "1", "test_challenge")
recs, err := in.ReadInstanceRecords()
if err != nil {
log.Fatal(err)
Expand Down
Binary file removed out/instanced
Binary file not shown.
23 changes: 6 additions & 17 deletions webserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ type InstancesResponse struct {
Action string `json:"action"`
Challenge string `json:"challenge"`
ID int64 `json:"id"`
URL string `json:"url"`
}

func (in *Instancer) handleLivenessCheck(c echo.Context) error {
Expand All @@ -31,14 +32,9 @@ func (in *Instancer) handleLivenessCheck(c echo.Context) error {

func (in *Instancer) handleInstanceCreate(c echo.Context) error {
chalName := c.QueryParam("chal")
token := c.QueryParam("token")
teamID := c.QueryParam("team")

// todo: check an auth token or something
if token == "" {
c.Logger().Info("request rejected with no token")
return c.JSON(http.StatusForbidden, "team token not provided")
}
rec, err := in.CreateInstance(chalName)
rec, err := in.CreateInstance(chalName, teamID)
if _, ok := err.(*ChallengeNotFoundError); ok {
return c.JSON(http.StatusNotFound, "challenge not supported")
}
Expand All @@ -49,25 +45,18 @@ func (in *Instancer) handleInstanceCreate(c echo.Context) error {
return c.JSON(http.StatusInternalServerError, "challenge deploy failed: contact admin")
}
c.Logger().Info("processed request to provision new instance")
return c.JSON(http.StatusAccepted, InstancesResponse{"created", chalName, rec.Id})
return c.JSON(http.StatusAccepted, InstancesResponse{"created", chalName, rec.Id, "TODO"})
}

func (in *Instancer) handleInstanceDelete(c echo.Context) error {
chalName := c.QueryParam("chal")
token := c.QueryParam("token")
instanceID, err := strconv.ParseInt(c.QueryParam("id"), 10, 64)

if err != nil {
return c.JSON(http.StatusBadRequest, "invalid id")
}

// todo: check an auth token or something
if token == "" {
c.Logger().Info("request rejected with no token")
return c.JSON(http.StatusForbidden, "team token not provided")
}

err = in.DestroyInstance(InstanceRecord{instanceID, time.Now(), chalName})
err = in.DestroyInstance(InstanceRecord{instanceID, time.Now(), chalName, ""})

if _, ok := err.(*ChallengeNotFoundError); ok {
return c.JSON(http.StatusNotFound, "challenge not supported")
Expand All @@ -80,7 +69,7 @@ func (in *Instancer) handleInstanceDelete(c echo.Context) error {
}
c.Logger().Info("processed request to destroy an instance")

return c.JSON(http.StatusAccepted, InstancesResponse{"destroyed", chalName, instanceID})
return c.JSON(http.StatusAccepted, InstancesResponse{"destroyed", chalName, instanceID, "TODO"})
}

func (in *Instancer) handleInstanceList(c echo.Context) error {
Expand Down

0 comments on commit 3bc0d8f

Please sign in to comment.