diff --git a/go.mod b/go.mod index 8eea991..e8de5cc 100644 --- a/go.mod +++ b/go.mod @@ -3,17 +3,18 @@ module github.com/CalebQ42/darkstorm-server go 1.22.5 require ( + github.com/CalebQ42/bbConvert v1.0.0 github.com/golang-jwt/jwt/v5 v5.2.1 github.com/google/uuid v1.6.0 go.mongodb.org/mongo-driver v1.15.1 golang.org/x/crypto v0.24.0 - github.com/CalebQ42/bbConvert v1.0.0 ) require ( github.com/golang/snappy v0.0.1 // indirect github.com/google/go-cmp v0.6.0 // indirect github.com/klauspost/compress v1.13.6 // indirect + github.com/lithammer/shortuuid/v3 v3.0.7 github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect diff --git a/go.sum b/go.sum index e6b8230..d51940b 100644 --- a/go.sum +++ b/go.sum @@ -8,10 +8,13 @@ github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= +github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8= +github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c= diff --git a/internal/blog/blog.go b/internal/blog/blog.go index 97bef80..bf0e518 100644 --- a/internal/blog/blog.go +++ b/internal/blog/blog.go @@ -213,8 +213,8 @@ func (b *BlogApp) reqLatestBlogs(w http.ResponseWriter, r *http.Request) { return } var ret struct { - Blogs []Blog `json:"blogs"` - Num int `json:"num"` + Blogs []*Blog `json:"blogs"` + Num int `json:"num"` } ret.Num = len(blogs) ret.Blogs = blogs diff --git a/internal/cdr/LICENSE b/internal/cdr/LICENSE new file mode 100644 index 0000000..cbf8dff --- /dev/null +++ b/internal/cdr/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Caleb Gardner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/internal/cdr/README.md b/internal/cdr/README.md new file mode 100644 index 0000000..0584b92 --- /dev/null +++ b/internal/cdr/README.md @@ -0,0 +1,44 @@ +# cdr-backend + +Stupid backend for [CDR]("https://github.com/CalebQ42/CustomDiceRoller"). + +## APIs + +### Dice + +Dice sharing + +> POST: /upload?key={api_key} + +Upload a die. + +Request Body: + +```json +{ + // Die data +} +``` + +Note: Only allows up to 1MB of data. If over 1MB returns 413. Further limits might be imposed in the future. + +Response: + +```json +{ + "id": "die ID", + "expiration": 0 // Unix time (Seconds) of expiration +} +``` + +> GET: /die/{die id}?key={api_key} + +Get an uploaded die. + +Response: + +```json +{ + // die data minus uid +} +``` diff --git a/internal/cdr/backend.go b/internal/cdr/backend.go new file mode 100644 index 0000000..55729fb --- /dev/null +++ b/internal/cdr/backend.go @@ -0,0 +1,61 @@ +package cdr + +import ( + "context" + "log" + "net/http" + "time" + + "github.com/CalebQ42/darkstorm-server/internal/backend" + "github.com/CalebQ42/darkstorm-server/internal/backend/db" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type CDRBackend struct { + back *backend.Backend + db *mongo.Database +} + +func NewBackend(back *backend.Backend, db *mongo.Database) *CDRBackend { + go func() { + for range time.Tick(time.Hour) { + log.Println("CDR: Deleting expired dice") + res, err := db.Collection("profiles").DeleteMany(context.TODO(), bson.M{"expiration": bson.M{"$lt": time.Now().Unix()}}) + if err == mongo.ErrNoDocuments { + continue + } + log.Println("CDR: Deleted", res.DeletedCount, "dice") + } + }() + return &CDRBackend{ + back: back, + db: db, + } +} + +func (b CDRBackend) AppID() string { + return "cdr" +} + +func (b CDRBackend) CountTable() backend.CountTable { + return db.NewMongoTable[backend.CountLog](b.db.Collection("logs")) +} + +func (b CDRBackend) CrashTable() backend.CrashTable { + return db.NewMongoCrashTable(b.db.Collection("crashes"), b.db.Collection("crashArchive")) +} + +func (s CDRBackend) AddCrash(cr backend.IndividualCrash) bool { + res := s.db.Collection("versions").FindOne(context.TODO(), bson.M{"version": cr.Version}) + return res.Err() != mongo.ErrNoDocuments +} + +func (b CDRBackend) Extension(mux *http.ServeMux) { + mux.HandleFunc("POST /cdr/die", b.UploadDie) + mux.HandleFunc("GET /cdr/die/{dieID}", b.GetDie) + + //Legacy (TODO: remove this after a month or two after the applciation gets updated) + mux.HandleFunc("POST /upload", b.UploadDie) + mux.HandleFunc("GET /die/{dieID}", b.GetDie) +} diff --git a/internal/cdr/die.go b/internal/cdr/die.go new file mode 100644 index 0000000..d49685b --- /dev/null +++ b/internal/cdr/die.go @@ -0,0 +1,83 @@ +package cdr + +import ( + "context" + "encoding/json" + "io" + "log" + "net/http" + "time" + + "github.com/CalebQ42/darkstorm-server/internal/backend" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type UploadedDie struct { + Die map[string]any `json:"die" bson:"die"` + ID string `json:"id" bson:"_id"` + Expiration int64 `json:"expiration" bson:"expiration"` +} + +func (b CDRBackend) UploadDie(w http.ResponseWriter, r *http.Request) { + hdr, err := b.back.VerifyHeader(w, r, "rooms", false) + if err != nil { + + } + if r.Body == nil { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } + bod, err := io.ReadAll(r.Body) + r.Body.Close() + if err != nil { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } + if len(bod) > 1048576 { //1MB + backend.ReturnError(w, http.StatusRequestEntityTooLarge, "too large", "Die is too large to upload") + return + } + var toUpload = UploadedDie{ + Die: make(map[string]any), + ID: uuid.New().String(), + Expiration: time.Now().Add(12 * time.Hour).Round(time.Hour).Unix(), + } + err = json.Unmarshal(bod, &toUpload.Die) + if err != nil { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } + if toUpload.Die["uuid"] != nil { + delete(toUpload.Die, "uuid") + } + _, err = b.db.Collection("dice").InsertOne(context.TODO(), toUpload) + if err != nil { + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + log.Println("error inserting die:", err) + return + } + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(map[string]any{"id": toUpload.ID, "expiration": toUpload.Expiration}) +} + +func (b CDRBackend) GetDie(w http.ResponseWriter, r *http.Request) { + res := b.db.Collection("dice").FindOne(context.TODO(), bson.M{"_id": r.PathValue("dieID")}) + if res.Err() == mongo.ErrNoDocuments { + backend.ReturnError(w, 404, "not found", "Die with the given id is not found") + return + } else if res.Err() != nil { + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + log.Println("error getting CDR die:", res.Err()) + return + } + var dieGet UploadedDie + err := res.Decode(&dieGet) + if err != nil { + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + log.Println("error decoding die:", err) + return + } + json.NewEncoder(w).Encode(dieGet.Die) +} diff --git a/internal/swassistant/LICENSE b/internal/swassistant/LICENSE new file mode 100644 index 0000000..c3fb973 --- /dev/null +++ b/internal/swassistant/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Caleb Gardner + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/internal/swassistant/README.md b/internal/swassistant/README.md new file mode 100644 index 0000000..eec094d --- /dev/null +++ b/internal/swassistant/README.md @@ -0,0 +1,108 @@ +# swassistant-backend + +Custom backend for [SWAssistant](https://github.com/CalebQ42/SWAssistant). Extension of [darkstorm-backend](https://github.com/CalebQ42/darkstorm-server/tree/main/internal/backend) + +## APIs + +For `POST` requests, the `X-API-Key` http header must be set. + +### Profiles + +#### Upload profile to share + +Character, vehicles, and minion profiles. + +> POST: /profile?type={character|vehicle|minion} + +Upload a profile. `type` query is required. + +Request Body: + +```json +{ + // profile data +} +``` + +Note: Only allows up to 5MB of data. If over 5MB returns 413. Further limits might be imposed in the future. + +Response: + +```json +{ + "id": "profile ID", + "expiration": 0 // Unix time (Seconds) of expiration +} +``` + +#### Get a shared profile + +> GET: /profile/{profileID} + +Get an uploaded profile. + +Response: + +```json +{ + "type": "character|vehicle|minion", + // profile data minus uid +} +``` + +### Rooms + +All room requests must include both `X-API-Key` and `Authorization` headers. + +#### Room list + +> GET: /rooms + +Get a list of rooms your currently a part of. + +Response: + +```json +[ + { + "id": "room ID", + "name": "room name", + "owner": "username" + } +] +``` + +#### Create new room + +> POST: /rooms/new?name={roomName} + +Create a new room. `name` query is required. + +Response: + +```json +{ + "id": "room ID", + "name": "room name" +} +``` + +#### Get room info + +> GET: /rooms/{roomID} + +Get info about a room. + +```json +{ + "id": "room ID", + "name": "room name", + "owner": "username", + "users": [ + "username" + ], + "profiles": [ + "profile uuids" + ] +} +``` diff --git a/internal/swassistant/main.go b/internal/swassistant/main.go new file mode 100644 index 0000000..5206311 --- /dev/null +++ b/internal/swassistant/main.go @@ -0,0 +1,69 @@ +package swassistant + +import ( + "context" + "log" + "net/http" + "time" + + "github.com/CalebQ42/darkstorm-server/internal/backend" + "github.com/CalebQ42/darkstorm-server/internal/backend/db" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type SWBackend struct { + back *backend.Backend + db *mongo.Database +} + +func NewSWBackend(back *backend.Backend, db *mongo.Database) *SWBackend { + go func() { + for range time.Tick(time.Hour) { + log.Println("SWAssistant: Deleting expired profiles") + res, err := db.Collection("profiles").DeleteMany(context.TODO(), bson.M{"expiration": bson.M{"$lt": time.Now().Unix()}}) + if err == mongo.ErrNoDocuments { + continue + } + log.Println("SWAssistant: Deleted", res.DeletedCount, "profiles") + } + }() + return &SWBackend{ + back: back, + db: db, + } +} + +func (s *SWBackend) AppID() string { + return "swassistant" +} + +func (s *SWBackend) CountTable() backend.CountTable { + return db.NewMongoTable[backend.CountLog](s.db.Collection("logs")) +} + +func (s *SWBackend) CrashTable() backend.CrashTable { + return db.NewMongoCrashTable(s.db.Collection("crashes"), s.db.Collection("crashArchive")) +} + +func (s *SWBackend) AddCrash(cr backend.IndividualCrash) bool { + res := s.db.Collection("versions").FindOne(context.TODO(), bson.M{"version": cr.Version}) + return res.Err() != mongo.ErrNoDocuments +} + +func (s *SWBackend) Extension(mux *http.ServeMux) { + mux.HandleFunc("GET /swa/room", s.ListRooms) + mux.HandleFunc("POST /swa/room", s.NewRoom) + mux.HandleFunc("GET /swa/room/{roomID}", s.GetRoom) + + mux.HandleFunc("POST /swa/profile", s.UploadProfile) + mux.HandleFunc("GET /swa/profile/{profileID}", s.GetProfile) + + //Legacy (TODO: remove this after a month or two after the applciation gets updated) + mux.HandleFunc("GET /room/list", s.ListRooms) + mux.HandleFunc("POST /room/new", s.NewRoom) + mux.HandleFunc("GET /room/{roomID}", s.GetRoom) + + mux.HandleFunc("POST /profile/upload", s.UploadProfile) + mux.HandleFunc("GET /profile/{profileID}", s.GetProfile) +} diff --git a/internal/swassistant/profile.go b/internal/swassistant/profile.go new file mode 100644 index 0000000..4926328 --- /dev/null +++ b/internal/swassistant/profile.go @@ -0,0 +1,93 @@ +package swassistant + +import ( + "context" + "encoding/json" + "io" + "log" + "net/http" + "time" + + "github.com/CalebQ42/darkstorm-server/internal/backend" + "github.com/lithammer/shortuuid/v3" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" +) + +type UploadedProf struct { + Profile map[string]any `json:"profile" bson:"profile"` + ID string `json:"id" bson:"_id"` + Type string `json:"type" bson:"type"` + Expiration int64 `json:"expiration" bson:"expiration"` +} + +func (s *SWBackend) UploadProfile(w http.ResponseWriter, r *http.Request) { + hdr, err := s.back.VerifyHeader(w, r, "profile", false) + if err != nil { + return + } + if hdr.Key.AppID != "swassistant" { + backend.ReturnError(w, http.StatusUnauthorized, "unauthorized", "Application not authorized") + return + } + profType := r.URL.Query().Get("type") + if profType == "" || (profType != "character" && profType != "vehicle" && profType != "minion") { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } + if r.Body == nil { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } + data, err := io.ReadAll(r.Body) + r.Body.Close() + if err != nil || len(data) == 0 { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } else if len(data) > 5242880 { // 5MB + backend.ReturnError(w, http.StatusRequestEntityTooLarge, "too large", "Profile is too large") + return + } + prof := make(map[string]any) + err = json.Unmarshal(data, &prof) + if err != nil { + backend.ReturnError(w, http.StatusBadRequest, "bad request", "Application sent a bad request") + return + } + delete(prof, "uid") + toUpload := UploadedProf{ + ID: shortuuid.New(), + Expiration: time.Now().Add(time.Hour * 12).Round(time.Hour).Unix(), + Type: profType, + Profile: prof, + } + _, err = s.db.Collection("profiles").InsertOne(context.TODO(), toUpload) + if err != nil { + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + log.Println("error inserting profile:", err) + return + } + w.WriteHeader(http.StatusCreated) + json.NewEncoder(w).Encode(map[string]any{"id": toUpload.ID, "expiration": toUpload.Expiration}) +} + +func (s *SWBackend) GetProfile(w http.ResponseWriter, r *http.Request) { + res := s.db.Collection("profiles").FindOne(context.TODO(), bson.M{"_id": r.PathValue("profileID")}) + if res.Err() == mongo.ErrNoDocuments { + backend.ReturnError(w, 404, "not found", "Profile not found") + return + } else if res.Err() != nil { + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + log.Println("error getting profile:", res.Err()) + return + } + var prof UploadedProf + err := res.Decode(&prof) + if err != nil { + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + log.Println("error decoding profile:", err) + return + } + prof.Profile["type"] = prof.Type + json.NewEncoder(w).Encode(prof.Profile) +} diff --git a/internal/swassistant/room.go b/internal/swassistant/room.go new file mode 100644 index 0000000..e171ff1 --- /dev/null +++ b/internal/swassistant/room.go @@ -0,0 +1,144 @@ +package swassistant + +import ( + "context" + "encoding/json" + "log" + "net/http" + + "github.com/CalebQ42/darkstorm-server/internal/backend" + "github.com/google/uuid" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" +) + +type Room struct { + ID string `json:"id" bson:"_id"` + Name string `json:"name" bson:"name"` + Owner string `json:"owner" bson:"owner"` + Users []string `json:"users" bson:"users"` + Profiles []string `json:"profiles" bson:"profiles"` +} + +func (s *SWBackend) ListRooms(w http.ResponseWriter, r *http.Request) { + hdr, err := s.back.VerifyHeader(w, r, "rooms", false) + if err != nil { + return + } + if hdr.Key.AppID != "swassistant" || hdr.User == nil { + backend.ReturnError(w, http.StatusUnauthorized, "unauthorized", "Application not authorized") + return + } + res, err := s.db.Collection("rooms").Find(context.TODO(), bson.M{"users": hdr.User.Username}, options.Find().SetProjection(bson.M{"_id": 1, "name": 1, "owner": 1})) + if err != nil && err != mongo.ErrNoDocuments { + log.Println("error getting room list:", err) + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + return + } + out := make([]struct { + ID string `json:"id" bson:"_id"` + Name string `json:"name" bson:"name"` + Owner string `json:"owner" bson:"owner"` + }, 0) + if err == nil { + err = res.All(context.TODO(), &out) + if err != nil { + log.Println("error decoding room list:", err) + backend.ReturnError(w, http.StatusInternalServerError, "internal", "Server error") + return + } + } + json.NewEncoder(w).Encode(out) +} + +func (s *SWBackend) NewRoom(w http.ResponseWriter, r *http.Request) { + hdr, err := s.back.VerifyHeader(w, r, "rooms", false) + if err != nil { + return + } + if hdr.Key.AppID != "swassistant" || hdr.User == nil { + backend.ReturnError(w, http.StatusUnauthorized, "unauthorized", "Application not authorized") + return + } + if req.Method != http.MethodPost || req.Query["name"] == nil || len(req.Query["name"]) != 1 || req.Query["name"][0] == "" { + req.Resp.WriteHeader(http.StatusBadRequest) + return true + } else if req.User == nil { + req.Resp.WriteHeader(http.StatusUnauthorized) + return true + } + //TODO: check room name for unsavory words + newRoom := Room{ + ID: uuid.NewString(), + Name: req.Query["name"][0], + Owner: req.User.Username, + Users: []string{}, + Profiles: []string{}, + } + _, err := s.db.Collection("rooms").InsertOne(context.TODO(), newRoom) + if err != nil { + log.Println("SWAssistant: Error creating room:", err) + req.Resp.WriteHeader(http.StatusInternalServerError) + return true + } + out, err := json.Marshal(map[string]string{"id": newRoom.ID, "name": newRoom.Name}) + if err != nil { + log.Println("SWAssistant: Error encoding new room:", err) + req.Resp.WriteHeader(http.StatusInternalServerError) + return true + } + req.Resp.WriteHeader(http.StatusCreated) + _, err = req.Resp.Write(out) + if err != nil { + log.Println("SWAssistant: Error writing new room:", err) + req.Resp.WriteHeader(http.StatusInternalServerError) + } + return true +} + +func (s *SWBackend) GetRoom(w http.ResponseWriter, r *http.Request) { + hdr, err := s.back.VerifyHeader(w, r, "rooms", false) + if err != nil { + return + } + if hdr.Key.AppID != "swassistant" || hdr.User == nil { + backend.ReturnError(w, http.StatusUnauthorized, "unauthorized", "Application not authorized") + return + } + if req.Method != http.MethodGet { + req.Resp.WriteHeader(http.StatusBadRequest) + return true + } else if req.User == nil { + req.Resp.WriteHeader(http.StatusUnauthorized) + return true + } + res := s.db.Collection("rooms").FindOne(context.TODO(), bson.M{"_id": req.Path[1]}) + if res.Err() == mongo.ErrNoDocuments { + req.Resp.WriteHeader(http.StatusNotFound) + return true + } else if res.Err() != nil { + log.Println("SWAssistant: Error getting room:", res.Err()) + req.Resp.WriteHeader(http.StatusInternalServerError) + return true + } + r := Room{} + err := res.Decode(&r) + if err != nil { + log.Println("SWAssistant: Error decoding room:", err) + req.Resp.WriteHeader(http.StatusInternalServerError) + return true + } + out, err := json.Marshal(r) + if err != nil { + log.Println("SWAssistant: Error encoding room:", err) + req.Resp.WriteHeader(http.StatusInternalServerError) + return true + } + _, err = req.Resp.Write(out) + if err != nil { + log.Println("SWAssistant: Error writing room:", err) + req.Resp.WriteHeader(http.StatusInternalServerError) + } + return true +} diff --git a/main.go b/main.go index 130c2d7..69038c1 100644 --- a/main.go +++ b/main.go @@ -14,6 +14,8 @@ import ( "github.com/CalebQ42/darkstorm-server/internal/backend" "github.com/CalebQ42/darkstorm-server/internal/backend/db" "github.com/CalebQ42/darkstorm-server/internal/blog" + "github.com/CalebQ42/darkstorm-server/internal/cdr" + "github.com/CalebQ42/darkstorm-server/internal/swassistant" "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" ) @@ -65,19 +67,15 @@ func setupMongo(uri string) { } func setupBackend(mux *http.ServeMux) { - testApp := backend.NewSimpleApp("testing", - db.NewMongoTable[backend.CountLog](mongoClient.Database("testing").Collection("count")), - db.NewMongoCrashTable( - mongoClient.Database("testing").Collection("crash"), - mongoClient.Database("testing").Collection("archive"), - )) blogApp = blog.NewBlogApp(back, mongoClient.Database("blog")) - //TODO: SWAssistant and CDR backends + swApp := swassistant.NewSWBackend(back, mongoClient.Database("swassistant")) + cdrApp := cdr.NewBackend(back, mongoClient.Database("cdr")) var err error back, err = backend.NewBackend(db.NewMongoTable[backend.ApiKey]( mongoClient.Database("darkstorm").Collection("keys")), - testApp, blogApp, + swApp, + cdrApp, ) if err != nil { log.Fatal("error setting up backend:", err)