-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add #249 Integrate API key endpoints
- Loading branch information
Showing
18 changed files
with
399 additions
and
144 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | ||
} |
Oops, something went wrong.