Skip to content

Commit

Permalink
Add #249 Integrate API key endpoints
Browse files Browse the repository at this point in the history
  • Loading branch information
albinpa committed Oct 20, 2023
1 parent 19a326e commit 3e1f2a8
Show file tree
Hide file tree
Showing 18 changed files with 399 additions and 144 deletions.
1 change: 1 addition & 0 deletions src/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ type Configuration struct {
Organization Organization
Type OrgType
User User
ApiSecretKey string
Iam Iam
Twilio Twilio
Firebase Firebase
Expand Down
2 changes: 2 additions & 0 deletions src/config/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ const (
IndividualId = "individualId"
DeliveryId = "deliveryId"
IdpId = "idpId"
ApiKeyId = "apiKeyId"
IndividualHeaderKey = "X-ConsentBB-IndividualId"
)

// Schemas
Expand Down
5 changes: 5 additions & 0 deletions src/database/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ func Init(config *config.Configuration) error {
return err
}

err = initCollection("apiKeys", []string{"id"}, true)
if err != nil {
return err
}

return nil
}

Expand Down
12 changes: 12 additions & 0 deletions src/token/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ const tokenKey = "token"
const userIDKey = "userID"
const rolesKey = "roles"
const APIKey = "apiKey"
const UserRoleKey = "role"

// Set Set the token to context
func Set(r *http.Request, token AccessToken) {
Expand Down Expand Up @@ -142,6 +143,9 @@ func SetUserID(r *http.Request, userID string) {

// GetUserID Get UserID from context
func GetUserID(r *http.Request) string {
if context.Get(r, userIDKey) == nil {
return ""
}
return context.Get(r, userIDKey).(string)
}

Expand Down Expand Up @@ -175,3 +179,11 @@ func IsOrgAdmin(r *http.Request) bool {
}
return false
}

func SetUserRole(r *http.Request, userRole string) {
context.Set(r, UserRoleKey, userRole)
}

func GetUserRole(r *http.Request) string {
return context.Get(r, UserRoleKey).(string)
}
72 changes: 72 additions & 0 deletions src/v2/apikey/apikey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package apikey

import (
"errors"
"fmt"
"time"

"github.com/bb-consent/api/src/config"
"github.com/dgrijalva/jwt-go"
"go.mongodb.org/mongo-driver/bson/primitive"
)

type ApiKey struct {
Id primitive.ObjectID `json:"id" bson:"_id,omitempty"`
Scopes []string `json:"scopes" valid:"required"`
Apikey string `json:"apiKey"`
ExpiryInDays int `json:"expiryInDays"`
OrganisationId string `json:"-"`
IsDeleted bool `json:"-"`
}

var ApiSecretKey string

func Init(config *config.Configuration) {
ApiSecretKey = config.ApiSecretKey

}

type Claims struct {
Scopes []string
// Add other fields as needed
jwt.StandardClaims
}

// Create Create apikey
func Create(scopes []string, expiresAt int64) (string, error) {
var SigningKey = []byte(ApiSecretKey)
// Create the Claims
claims := Claims{
scopes,
jwt.StandardClaims{

ExpiresAt: expiresAt,
},
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
ss, err := token.SignedString(SigningKey)

return ss, err
}

// Decode Decodes the apikey
func Decode(apiKey string) (claims Claims, err error) {
var SigningKey = []byte(ApiSecretKey)
token, err := jwt.ParseWithClaims(apiKey, &claims, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return SigningKey, nil
})

if err != nil || !token.Valid {
return claims, err
}

//Check the token expiry
if int64(claims.StandardClaims.ExpiresAt) < time.Now().Unix() {
return claims, errors.New("token expired")
}
return claims, nil
}
62 changes: 62 additions & 0 deletions src/v2/apikey/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package apikey

import (
"context"

"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/database"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
"go.mongodb.org/mongo-driver/mongo"
)

func Collection() *mongo.Collection {
return database.DB.Client.Database(database.DB.Name).Collection("apiKeys")
}

type ApiKeyRepository struct {
DefaultFilter bson.M
}

// Init
func (apiKeyRepo *ApiKeyRepository) Init(organisationId string) {
apiKeyRepo.DefaultFilter = bson.M{"organisationid": organisationId, "isdeleted": false}
}

// Add Adds the data agreement to the db
func (apiKeyRepo *ApiKeyRepository) Add(apiKey ApiKey) (ApiKey, error) {

_, err := Collection().InsertOne(context.TODO(), apiKey)
if err != nil {
return ApiKey{}, err
}

return apiKey, nil
}

// Get Gets a single data agreement by given id
func (apiKeyRepo *ApiKeyRepository) Get(apiKeyID string) (ApiKey, error) {
apiKeyId, err := primitive.ObjectIDFromHex(apiKeyID)
if err != nil {
return ApiKey{}, err
}

filter := common.CombineFilters(apiKeyRepo.DefaultFilter, bson.M{"_id": apiKeyId})

var result ApiKey
err = Collection().FindOne(context.TODO(), filter).Decode(&result)
return result, err
}

// Update Updates the data agreement
func (apiKeyRepo *ApiKeyRepository) Update(apiKey ApiKey) (ApiKey, error) {

filter := common.CombineFilters(apiKeyRepo.DefaultFilter, bson.M{"_id": apiKey.Id})
update := bson.M{"$set": apiKey}

_, err := Collection().UpdateOne(context.TODO(), filter, update)
if err != nil {
return ApiKey{}, err
}
return apiKey, nil
}
77 changes: 77 additions & 0 deletions src/v2/handler/apikey/config_create_apikey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package apikey

import (
"encoding/json"
"fmt"
"io"
"net/http"
"time"

"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/config"
"github.com/bb-consent/api/src/v2/apikey"
"go.mongodb.org/mongo-driver/bson/primitive"
)

type addApiKeyReq struct {
Apikey apikey.ApiKey `json:"apiKey" valid:"required"`
}

type addApiKeyResp struct {
Apikey apikey.ApiKey `json:"apiKey" valid:"required"`
}

// ConfigCreateApiKey
func ConfigCreateApiKey(w http.ResponseWriter, r *http.Request) {

// Headers
organisationId := r.Header.Get(config.OrganizationId)
organisationId = common.Sanitize(organisationId)

// Request body
var apiKeyReq addApiKeyReq
b, _ := io.ReadAll(r.Body)
defer r.Body.Close()
json.Unmarshal(b, &apiKeyReq)

// Repository
apiKeyRepo := apikey.ApiKeyRepository{}
apiKeyRepo.Init(organisationId)

expiryAt := int64(apiKeyReq.Apikey.ExpiryInDays)
if expiryAt <= 0 {
//Default apikey expiry 1 month
expiryAt = time.Now().Unix() + 60*60*24*30
apiKeyReq.Apikey.ExpiryInDays = 30
}

key, err := apikey.Create(apiKeyReq.Apikey.Scopes, expiryAt)
if err != nil {
m := "Failed to create apiKey"
common.HandleError(w, http.StatusInternalServerError, m, err)
return
}

var newApiKey apikey.ApiKey
newApiKey.Id = primitive.NewObjectID()
newApiKey.Scopes = apiKeyReq.Apikey.Scopes
newApiKey.Apikey = key
newApiKey.ExpiryInDays = apiKeyReq.Apikey.ExpiryInDays
newApiKey.OrganisationId = organisationId
newApiKey.IsDeleted = false

apiKey, err := apiKeyRepo.Add(newApiKey)
if err != nil {
m := fmt.Sprintf("Failed to add api key: %v", organisationId)
common.HandleErrorV2(w, http.StatusInternalServerError, m, err)
return
}

resp := addApiKeyResp{
Apikey: apiKey,
}
response, _ := json.Marshal(resp)
w.Header().Set(config.ContentTypeHeader, config.ContentTypeJSON)
w.WriteHeader(http.StatusOK)
w.Write(response)
}
51 changes: 51 additions & 0 deletions src/v2/handler/apikey/config_delete_apikey.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package apikey

import (
"encoding/json"
"net/http"

"github.com/bb-consent/api/src/common"
"github.com/bb-consent/api/src/config"
"github.com/bb-consent/api/src/v2/apikey"
"github.com/gorilla/mux"
)

type deleteApiKeyResp struct {
Apikey apikey.ApiKey `json:"apiKey" valid:"required"`
}

// ConfigDeleteAPIKey
func ConfigDeleteApiKey(w http.ResponseWriter, r *http.Request) {
// Headers
organisationId := r.Header.Get(config.OrganizationId)
organisationId = common.Sanitize(organisationId)

apiKeyId := mux.Vars(r)[config.ApiKeyId]
apiKeyId = common.Sanitize(apiKeyId)

// Repository
apiKeyRepo := apikey.ApiKeyRepository{}
apiKeyRepo.Init(organisationId)
apiKey, err := apiKeyRepo.Get(apiKeyId)
if err != nil {
m := "Failed to remove api key for organisation"
common.HandleError(w, http.StatusInternalServerError, m, err)
return
}
apiKey.IsDeleted = true

// Deletes api key
apiKey, err = apiKeyRepo.Update(apiKey)
if err != nil {
m := "Failed to remove api key for organisation "
common.HandleError(w, http.StatusInternalServerError, m, err)
return
}
resp := deleteApiKeyResp{
Apikey: apiKey,
}
response, _ := json.Marshal(resp)
w.Header().Set(config.ContentTypeHeader, config.ContentTypeJSON)
w.WriteHeader(http.StatusOK)
w.Write(response)
}
Loading

0 comments on commit 3e1f2a8

Please sign in to comment.