Skip to content

Commit

Permalink
Merge pull request #197 from Real-Dev-Squad/sendBlockingMessageToDiscord
Browse files Browse the repository at this point in the history
Send blocking message to discord
  • Loading branch information
lakshayman authored Feb 21, 2024
2 parents 0f64aa3 + a5f360f commit 9adbdab
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 26 deletions.
1 change: 1 addition & 0 deletions call-profile/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/aws/aws-lambda-go v1.41.0
github.com/aws/aws-sdk-go v1.44.284
github.com/go-ozzo/ozzo-validation/v4 v4.3.0
github.com/golang-jwt/jwt/v5 v5.2.0
golang.org/x/crypto v0.14.0
google.golang.org/api v0.128.0
)
Expand Down
2 changes: 2 additions & 0 deletions call-profile/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0 h1:byhDUpfEwjsVQb1vBunvIjh2BHQ9ead57VkAEY4V+Es=
github.com/go-ozzo/ozzo-validation/v4 v4.3.0/go.mod h1:2NKgrcHl3z6cJs+3Oo940FPRiTzuqKbvfrL2RxCj6Ew=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
Expand Down
90 changes: 72 additions & 18 deletions call-profile/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"os"
"sync"
"time"
"bytes"

"cloud.google.com/go/firestore"
firebase "firebase.google.com/go"
Expand All @@ -25,6 +26,7 @@ import (
// validation packages
"github.com/go-ozzo/ozzo-validation/v4"
"github.com/go-ozzo/ozzo-validation/v4/is"
"github.com/golang-jwt/jwt/v5"
)

var wg sync.WaitGroup
Expand Down Expand Up @@ -87,6 +89,10 @@ type structProfilesSkipped struct {
OtherError []string
}

type Claims struct {
jwt.RegisteredClaims
}

/*
Structures Conversions
*/
Expand Down Expand Up @@ -155,6 +161,8 @@ var Constants map[string]string = map[string]string{
"ENV_PRODUCTION": "PRODUCTION",
"STORED": "stored",
"FIRE_STORE_CRED": "firestoreCred",
"DISCORD_BOT_URL": "discordBotURL",
"IDENTITY_SERVICE_PRIVATE_KEY": "identityServicePrivateKey",
"PROFILE_SERVICE_HEALTH": "PROFILE_SERVICE_HEALTH",
"PROFILE_SKIPPED": "PROFILE_SKIPPED",
"PROFILE_DIFF_STORED": "PROFILE_DIFF_STORED",
Expand All @@ -173,11 +181,11 @@ var Constants map[string]string = map[string]string{
/*
Setting Firestore Key for development/production
*/
func getFirestoreKey() string {
func getParameter(parameter string) string {
if os.Getenv(("environment")) == Constants["ENV_DEVELOPMENT"] {
return os.Getenv(Constants["FIRE_STORE_CRED"])
return os.Getenv(parameter)
} else if os.Getenv(("environment")) == Constants["ENV_PRODUCTION"] {
var parameterName string = Constants["FIRE_STORE_CRED"]
var parameterName string = parameter

sess := session.Must(session.NewSessionWithOptions(session.Options{
SharedConfigState: session.SharedConfigEnable,
Expand Down Expand Up @@ -206,7 +214,7 @@ func getFirestoreKey() string {
Function to initialize the firestore client
*/
func initializeFirestoreClient(ctx context.Context) (*firestore.Client, error) {
sa := option.WithCredentialsJSON([]byte(getFirestoreKey()))
sa := option.WithCredentialsJSON([]byte(getParameter(Constants["FIRE_STORE_CRED"])))
app, err := firebase.NewApp(ctx, nil, sa)
if err != nil {
return nil, err
Expand Down Expand Up @@ -234,6 +242,29 @@ func (res Res) Validate() error {
validation.Field(&res.Website, is.URL))
}

/*
Functions to generate jwt token
*/

func generateJWTToken() string {
signKey, errGeneratingRSAKey := jwt.ParseRSAPrivateKeyFromPEM([]byte(getParameter(Constants["IDENTITY_SERVICE_PRIVATE_KEY"])))
if(errGeneratingRSAKey != nil) {
return "";
}
expirationTime := time.Now().Add(1 * time.Minute)
t := jwt.New(jwt.GetSigningMethod("RS256"))
t.Claims = &Claims{
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expirationTime),
},
}
tokenString, err := t.SignedString(signKey)
if(err != nil) {
return "";
}
return tokenString
}

/*
MODELS
*/
Expand Down Expand Up @@ -294,12 +325,28 @@ func logProfileStored(client *firestore.Client, ctx context.Context, userId stri
/*
Function for setting the profileStatus in user object in firestore
*/
func setProfileStatusBlocked(client *firestore.Client, ctx context.Context, userId string, reason string, sessionId string) {
func setProfileStatusBlocked(client *firestore.Client, ctx context.Context, userId string, reason string, sessionId string, discordId string) {
client.Collection("users").Doc(userId).Set(ctx, map[string]interface{}{
"profileStatus": Constants["STATUS_BLOCKED"],
"chaincode": "",
}, firestore.MergeAll)

if discordId != "" {
tokenString := generateJWTToken();
postBody, _ := json.Marshal(map[string]string{
"userId": discordId,
"reason": reason,
})

responseBody := bytes.NewBuffer(postBody)

httpClient := &http.Client{}
req, _ := http.NewRequest("POST", os.Getenv(Constants["DISCORD_BOT_URL"]) + "/profile/blocked", responseBody)
req.Header.Add("Content-Type", "application/json")
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", tokenString))
httpClient.Do(req)
}

newLog := Log{
Type: Constants["PROFILE_SERVICE_BLOCKED"],
Timestamp: time.Now(),
Expand Down Expand Up @@ -364,13 +411,13 @@ func generateAndStoreDiff(client *firestore.Client, ctx context.Context, res Res
/*
Getting data from the user's service
*/
func getdata(client *firestore.Client, ctx context.Context, userId string, userUrl string, chaincode string, userData Res, sessionId string) string {
func getdata(client *firestore.Client, ctx context.Context, userId string, userUrl string, chaincode string, userData Res, sessionId string, discordId string) string {
var status string = ""
userUrl = userUrl + "profile"
hashedChaincode, err := bcrypt.GenerateFromPassword([]byte(chaincode), bcrypt.DefaultCost)
if err != nil {
logProfileSkipped(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId, discordId)
return "chaincode not encrypted"
}

Expand All @@ -380,18 +427,18 @@ func getdata(client *firestore.Client, ctx context.Context, userId string, userU
resp, err := httpClient.Do(req)
if err != nil {
logProfileSkipped(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId, discordId)
return "error getting profile data"
}
if resp.StatusCode == 401 {
logProfileSkipped(client, ctx, userId, "Unauthenticated Access to Profile Data", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Unauthenticated Access to Profile Data", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Unauthenticated Access to Profile Data", sessionId, discordId)
resp.Body.Close()
return "unauthenticated access to profile data"
}
if resp.StatusCode != 200 {
logProfileSkipped(client, ctx, userId, "Error in getting Profile Data", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Error in getting Profile Data", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Error in getting Profile Data", sessionId, discordId)
resp.Body.Close()
return "error in getting profile data"
}
Expand All @@ -401,22 +448,22 @@ func getdata(client *firestore.Client, ctx context.Context, userId string, userU
r, err := ioutil.ReadAll(resp.Body)
if err != nil {
logProfileSkipped(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId, discordId)
return "error reading profile data"
}
var res Res
err = json.Unmarshal([]byte(r), &res)
if err != nil {
logProfileSkipped(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId, discordId)
return "error converting data to json"
}

err = res.Validate()

if err != nil {
logProfileSkipped(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId)
setProfileStatusBlocked(client, ctx, userId, fmt.Sprintln(err), sessionId, discordId)
return fmt.Sprintf("error in validation: ", err)
}

Expand Down Expand Up @@ -481,22 +528,29 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo

var userUrl string
var chaincode string
var discordId string

if str, ok := dsnap.Data()["profileURL"].(string); ok {
userUrl = str
} else {
logProfileSkipped(client, ctx, userId, "Profile URL not available", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Profile URL not available", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Profile URL not available", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped No Profile URL",
StatusCode: 200,
}, nil
}

if str, ok := dsnap.Data()["discordId"].(string); ok {
discordId = str
} else {
discordId = ""
}

if str, ok := dsnap.Data()["chaincode"].(string); ok {
if str == "" {
logProfileSkipped(client, ctx, userId, "Profile Service Blocked or Chaincode is empty", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Profile Service Blocked or Chaincode is empty", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Profile Service Blocked or Chaincode is empty", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Profile Service Blocked",
StatusCode: 200,
Expand All @@ -505,7 +559,7 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo
chaincode = str
} else {
logProfileSkipped(client, ctx, userId, "Chaincode Not Found", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Chaincode Not Found", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Chaincode Not Found", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Chaincode Not Found",
StatusCode: 200,
Expand Down Expand Up @@ -539,14 +593,14 @@ func handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyRespo
logHealth(client, ctx, userId, isServiceRunning, sessionId)
if !isServiceRunning {
logProfileSkipped(client, ctx, userId, "Profile Service Down", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Profile Service Down", sessionId)
setProfileStatusBlocked(client, ctx, userId, "Profile Service Down", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Service Down",
StatusCode: 200,
}, nil
}

dataErr := getdata(client, ctx, userId, userUrl, chaincode, diffToRes(userData), sessionId)
dataErr := getdata(client, ctx, userId, userUrl, chaincode, diffToRes(userData), sessionId, discordId)
if dataErr != "" {
return events.APIGatewayProxyResponse{
Body: "Profile Skipped " + dataErr,
Expand Down
2 changes: 2 additions & 0 deletions template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ Globals:
firestoreCred: YourFirestoreCredentials
environment: PRODUCTION
baseURL: YourBaseAPIURL
discordBotURL: DiscordBotURL
identityServicePrivateKey: YourIdentityServicePrivateKey

Resources:
HealthFunction:
Expand Down
9 changes: 6 additions & 3 deletions verify/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ func TestGetUserIdFromBody(t *testing.T) {
type testVerifyData struct {
name string
path string
salt string
chaincode string
mockStatusCode int
mockResBody string
Expand All @@ -174,15 +175,17 @@ func TestVerify(t *testing.T) {
{
name: "VERIFIED",
path: "/profile-one",
salt: "testSalt",
chaincode: "testchaincode",
mockStatusCode: http.StatusOK,
mockResBody: `{"hash": "$2a$12$ScGc2Q0t0rqqSJK1E2W/WuaRVAchaVWdUqb1hQi21cFTnOVvlIdry"}`,
mockResBody: `{"hash": "cadf727ffff23ec46c17d808a4884ea7566765182d1a2ffa88e4719bc1f7f9fb328e2abacc13202f2dc55b9d653919b79ecf02dd752de80285bbec57a57713d9"}`,
expectedStatus: "VERIFIED",
expectedErr: nil,
},
{
name: "BLOCKED",
path: "/profile-two",
salt: "testSalt",
chaincode: "invalid",
mockStatusCode: http.StatusForbidden,
mockResBody: `{"hash": "abcdefghijklmnopqrstuvwxyz"}`,
Expand All @@ -194,7 +197,7 @@ func TestVerify(t *testing.T) {
server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.URL.Path == "/profile-one" {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"hash": "$2a$12$ScGc2Q0t0rqqSJK1E2W/WuaRVAchaVWdUqb1hQi21cFTnOVvlIdry"}`))
w.Write([]byte(`{"hash": "cadf727ffff23ec46c17d808a4884ea7566765182d1a2ffa88e4719bc1f7f9fb328e2abacc13202f2dc55b9d653919b79ecf02dd752de80285bbec57a57713d9"}`))
}

if r.URL.Path == "/profile-two" {
Expand All @@ -206,7 +209,7 @@ func TestVerify(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {

status, err := verify(server.URL+testCase.path, testCase.chaincode)
status, err := verify(server.URL+testCase.path, testCase.chaincode, testCase.salt)

assert.Equal(t, testCase.expectedStatus, status)
assert.Equal(t, testCase.expectedErr, err)
Expand Down
10 changes: 5 additions & 5 deletions verify/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,11 @@ func randSalt(n int) string {
/*
Function to verify the user
*/
func verify(profileURL string, chaincode string) (string, error) {
func verify(profileURL string, chaincode string, salt string) (string, error) {
type res struct {
Hash string `json:"hash"`
}

rand.Seed(time.Now().UnixNano())
var salt string = randSalt(21)

postBody, _ := json.Marshal(map[string]string{
"salt": salt,
})
Expand Down Expand Up @@ -284,7 +281,10 @@ func (d *deps) handler(request events.APIGatewayProxyRequest) (events.APIGateway
}, nil
}

status, err := verify(profileURL, chaincode)
rand.Seed(time.Now().UnixNano())
var salt string = randSalt(21)

status, err := verify(profileURL, chaincode, salt)
if err != nil {
logVerification(d.client, d.ctx, status, profileURL, userId)
setProfileStatus(d.client, d.ctx, userId, status)
Expand Down

0 comments on commit 9adbdab

Please sign in to comment.