Skip to content

Commit

Permalink
Merge branch 'main' into redux-persist
Browse files Browse the repository at this point in the history
  • Loading branch information
Alder Whiteford authored and Alder Whiteford committed May 29, 2024
2 parents ebdb117 + f2e2b0a commit 595dee8
Show file tree
Hide file tree
Showing 125 changed files with 7,624 additions and 6,496 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ frontend/mobile/android/
tmp/
ios
android
.idea/modules.xml
3 changes: 3 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
- [PostgreSQL](https://www.postgresql.org/)
- Install through brew: `brew install postgresql@15`
- It requires you to add all the exports to path so read the end of the installation carefully!
- [Redis](https://redis.io/docs/latest/operate/oss_and_stack/install/install-stack/)
- Install through brew: `brew tap redis-stack/redis-stack`
- Then install: `brew install redis-stack`
- [Trunk](https://marketplace.visualstudio.com/items?itemName=Trunk.io) (Recommended!)
- Visual Studio Code extension for linting/formatting
- [migrate](https://github.com/golang-migrate/migrate)
Expand Down
39 changes: 39 additions & 0 deletions backend/DEPLOYMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Configuration

SAC uses environment variables for configuration. SAC will, by default, pull the envvars from the process in which it was launched, but you can also pass in a .env file (using the --config flag) and use the values defined in there. See .env.template for an example .env file.

| Name | Group | Description |
|--------------------------------------|------------|---------------------------------------|
| SAC_APPLICATION_PORT | app | port to run the server on. |
| SAC_APPLICATION_HOST | app | host to run the server on. |
| SAC_APPLICATION_BASE_URL | app | base url to run the server on. |
| SAC_DB_USERNAME | db | username for database. |
| SAC_DB_PASSWORD | db | password for database. |
| SAC_DB_PORT | db | port for database. |
| SAC_DB_HOST | db | host for database. |
| SAC_DB_NAME | db | name of database. |
| SAC_DB_REQUIRE_SSL | db | if the db connection requires ssl. |
| SAC_REDIS_ACTIVE_TOKENS_USERNAME | redis | username for active tokens redis. |
| SAC_REDIS_ACTIVE_TOKENS_PASSWORD | redis | password for active tokens redis. |
| SAC_REDIS_ACTIVE_TOKENS_HOST | redis | host for active tokens redis. |
| SAC_REDIS_ACTIVE_TOKENS_PORT | redis | port for active tokens redis. |
| SAC_REDIS_ACTIVE_TOKENS_DB | redis | db for active tokens redis. |
| SAC_REDIS_BLACKLIST_USERNAME | redis | username for blacklist redis. |
| SAC_REDIS_BLACKLIST_PASSWORD | redis | password for blacklist redis. |
| SAC_REDIS_BLACKLIST_HOST | redis | host for blacklist redis. |
| SAC_REDIS_BLACKLIST_PORT | redis | port for blacklist redis. |
| SAC_REDIS_BLACKLIST_DB | redis | db for blacklist redis. |
| SAC_REDIS_LIMITER_USERNAME | redis | username for limiter redis. |
| SAC_REDIS_LIMITER_PASSWORD | redis | password for limiter redis. |
| SAC_REDIS_LIMITER_HOST | redis | host for limiter redis. |
| SAC_REDIS_LIMITER_PORT | redis | port for limiter redis. |
| SAC_REDIS_LIMITER_DB | redis | db for limiter redis. |
| SAC_SUDO_PASSWORD | superuser | password for the superuser. |
| SAC_AUTH_ACCESS_KEY | auth | access key for auth. |
| SAC_AUTH_REFRESH_KEY | auth | refresh key for auth. |
| SAC_AWS_BUCKET_NAME | aws | bucket name for aws s3. |
| SAC_AWS_ID | aws | id for aws s3. |
| SAC_AWS_SECRET | aws | secret for aws s3. |
| SAC_AWS_REGION | aws | region for aws s3. |
| SAC_RESEND_API_KEY | resend | api key for resend. |
| SAC_CALENDAR_MAX_TERMINATION_DATE | calendar | max termination date for calendar integrations. |
31 changes: 9 additions & 22 deletions backend/auth/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -276,35 +276,22 @@ func copyCustomClaims(claims *jwt.MapClaims, customClaims map[string]interface{}
}
}

func GenerateRefreshCookie(value string) *fiber.Cookie {
return &fiber.Cookie{
func SetResponseTokens(c *fiber.Ctx, tokens *Token) {
c.Set("Authorization", fmt.Sprintf("Bearer %s", tokens.AccessToken))
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: value,
Value: string(tokens.RefreshToken),
Expires: time.Now().Add(constants.REFRESH_TOKEN_EXPIRY),
HTTPOnly: true,
}
})
}

func SetResponseTokens(c *fiber.Ctx, tokens *Token) error {
// Set the tokens in the response
// should also blacklist the old refresh and access tokens

c.Set("Authorization", fmt.Sprintf("Bearer %s", tokens.AccessToken))
func ExpireResponseTokens(c *fiber.Ctx) {
c.Set("Authorization", "")
c.Cookie(&fiber.Cookie{
Name: "refresh_token",
Value: string(tokens.RefreshToken),
Expires: time.Now().Add(constants.REFRESH_TOKEN_EXPIRY),
Value: "",
Expires: time.Now().Add(-time.Hour),
HTTPOnly: true,
})

return nil
}

// func ExpireCookie(name string) *fiber.Cookie {
// return &fiber.Cookie{
// Name: name,
// Value: "",
// Expires: time.Now().Add(-time.Hour),
// HTTPOnly: true,
// }
// }
7 changes: 7 additions & 0 deletions backend/config/app.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package config

type ApplicationSettings struct {
Port uint16 `env:"PORT"`
Host string `env:"HOST"`
BaseUrl string `env:"BASE_URL"`
}
7 changes: 0 additions & 7 deletions backend/config/application.go

This file was deleted.

20 changes: 10 additions & 10 deletions backend/config/auth.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package config

import (
"errors"
"fmt"

m "github.com/garrettladley/mattress"
)
Expand All @@ -12,23 +12,23 @@ type AuthSettings struct {
}

type intermediateAuthSettings struct {
AccessKey string `yaml:"accesskey"`
RefreshKey string `yaml:"refreshkey"`
accessKey string `env:"ACCESS_KEY"`
refreshKey string `env:"REFRESH_KEY"`
}

func (int *intermediateAuthSettings) into() (*AuthSettings, error) {
accessToken, err := m.NewSecret(int.AccessKey)
func (i *intermediateAuthSettings) into() (*AuthSettings, error) {
accessKey, err := m.NewSecret(i.accessKey)
if err != nil {
return nil, errors.New("failed to create secret from access key")
return nil, fmt.Errorf("failed to create secret from access key: %s", err.Error())
}

refreshToken, err := m.NewSecret(int.RefreshKey)
refreshKey, err := m.NewSecret(i.refreshKey)
if err != nil {
return nil, errors.New("failed to create secret from refresh key")
return nil, fmt.Errorf("failed to create secret from refresh key: %s", err.Error())
}

return &AuthSettings{
AccessKey: accessToken,
RefreshKey: refreshToken,
AccessKey: accessKey,
RefreshKey: refreshKey,
}, nil
}
62 changes: 24 additions & 38 deletions backend/config/aws.go
Original file line number Diff line number Diff line change
@@ -1,64 +1,50 @@
package config

import (
"errors"
"os"
"fmt"

m "github.com/garrettladley/mattress"
)

type AWSSettings struct {
BUCKET_NAME *m.Secret[string]
ID *m.Secret[string]
SECRET *m.Secret[string]
REGION *m.Secret[string]
BucketName *m.Secret[string]
ID *m.Secret[string]
Secret *m.Secret[string]
Region *m.Secret[string]
}

func readAWSSettings() (*AWSSettings, error) {
bucketName := os.Getenv("SAC_AWS_BUCKET_NAME")
if bucketName == "" {
return nil, errors.New("SAC_AWS_BUCKET_NAME is not set")
}
type intermediateAWSSettings struct {
bucketName string `env:"BUCKET_NAME"`
id string `env:"ID"`
secret string `env:"SECRET"`
region string `env:"REGION"`
}

secretBucketName, err := m.NewSecret(bucketName)
func (i *intermediateAWSSettings) into() (*AWSSettings, error) {
bucketName, err := m.NewSecret(i.bucketName)
if err != nil {
return nil, errors.New("failed to create secret from bucket name")
}

id := os.Getenv("SAC_AWS_ID")
if id == "" {
return nil, errors.New("SAC_AWS_ID is not set")
return nil, fmt.Errorf("failed to create secret from bucket name: %s", err.Error())
}

secretID, err := m.NewSecret(id)
id, err := m.NewSecret(i.id)
if err != nil {
return nil, errors.New("failed to create secret from id")
return nil, fmt.Errorf("failed to create secret from ID: %s", err.Error())
}

secret := os.Getenv("SAC_AWS_SECRET")
if secret == "" {
return nil, errors.New("SAC_AWS_SECRET is not set")
}

secretSecret, err := m.NewSecret(secret)
secret, err := m.NewSecret(i.secret)
if err != nil {
return nil, errors.New("failed to create secret from secret")
}

region := os.Getenv("SAC_AWS_REGION")
if region == "" {
return nil, errors.New("SAC_AWS_REGION is not set")
return nil, fmt.Errorf("failed to create secret from secret: %s", err.Error())
}

reigonSecret, err := m.NewSecret(region)
region, err := m.NewSecret(i.region)
if err != nil {
return nil, errors.New("failed to create secret from region")
return nil, fmt.Errorf("failed to create secret from region: %s", err.Error())
}

return &AWSSettings{
BUCKET_NAME: secretBucketName,
ID: secretID,
SECRET: secretSecret,
REGION: reigonSecret,
BucketName: bucketName,
ID: id,
Secret: secret,
Region: region,
}, nil
}
11 changes: 6 additions & 5 deletions backend/config/calendar.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package config

import (
"fmt"
"time"
)

Expand All @@ -9,16 +10,16 @@ type CalendarSettings struct {
}

type intermediateCalendarSettings struct {
MaxTerminationDate string `yaml:"maxterminationdate"`
maxTerminationDate string `env:"MAX_TERMINATION_DATE"`
}

func (int *intermediateCalendarSettings) into() (*CalendarSettings, error) {
t, err := time.Parse("01-02-2006", int.MaxTerminationDate)
func (i *intermediateCalendarSettings) into() (*CalendarSettings, error) {
maxTerminationDate, err := time.Parse("01-02-2006", i.maxTerminationDate)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to parse max termination date: %s", err.Error())
}

return &CalendarSettings{
MaxTerminationDate: t,
MaxTerminationDate: maxTerminationDate,
}, nil
}
86 changes: 10 additions & 76 deletions backend/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,88 +2,22 @@ package config

import (
"fmt"
"os"

"github.com/spf13/viper"
"github.com/caarlos0/env/v11"
"github.com/joho/godotenv"
)

type Settings struct {
Application ApplicationSettings
Database DatabaseSettings
SuperUser SuperUserSettings
Auth AuthSettings
AWS AWSSettings
Pinecone PineconeSettings
OpenAI OpenAISettings
Resend ResendSettings
Calendar CalendarSettings
GoogleSettings OAuthSettings
OutlookSettings OAuthSettings
}

type intermediateSettings struct {
Application ApplicationSettings `yaml:"application"`
Database intermediateDatabaseSettings `yaml:"database"`
SuperUser intermediateSuperUserSettings `yaml:"superuser"`
Auth intermediateAuthSettings `yaml:"authsecret"`
Calendar intermediateCalendarSettings `yaml:"calendar"`
}

func (int *intermediateSettings) into() (*Settings, error) {
databaseSettings, err := int.Database.into()
if err != nil {
return nil, err
}

superUserSettings, err := int.SuperUser.into()
if err != nil {
return nil, err
}

authSettings, err := int.Auth.into()
func GetConfiguration(path string) (*Settings, error) {
err := godotenv.Load(path)
if err != nil {
return nil, err
return nil, fmt.Errorf("failed to load environment variables: %s", err.Error())
}

calendarSettings, err := int.Calendar.into()
if err != nil {
return nil, err
}

return &Settings{
Application: int.Application,
Database: *databaseSettings,
SuperUser: *superUserSettings,
Auth: *authSettings,
Calendar: *calendarSettings,
}, nil
}

type Environment string

const (
EnvironmentLocal Environment = "local"
EnvironmentProduction Environment = "production"
)

func GetConfiguration(path string, useDevDotEnv bool) (*Settings, error) {
var environment Environment
if env := os.Getenv("APP_ENVIRONMENT"); env != "" {
environment = Environment(env)
} else {
environment = "local"
var intermediateSettings intermediateSettings
if err := env.Parse(&intermediateSettings); err != nil {
return nil, fmt.Errorf("failed to parse environment variables: %s", err.Error())
}

v := viper.New()
v.SetConfigType("yaml")
v.AddConfigPath(path)

switch environment {
case EnvironmentLocal:
return readLocal(v, path, useDevDotEnv)
case EnvironmentProduction:
return readProd(v)
default:
return nil, fmt.Errorf("unknown environment: %s", environment)
}
settings, err := intermediateSettings.into()
return settings, err
}
Loading

0 comments on commit 595dee8

Please sign in to comment.