Skip to content

Commit

Permalink
Merge pull request #31 from abjrcode/write-dialog
Browse files Browse the repository at this point in the history
support saving AWS credentials to AWS credentials file
  • Loading branch information
abjrcode authored Dec 16, 2023
2 parents 530b9f3 + 99fb1f8 commit 310069c
Show file tree
Hide file tree
Showing 22 changed files with 1,020 additions and 788 deletions.
32 changes: 20 additions & 12 deletions app_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/abjrcode/swervo/internal/plumbing"
"github.com/abjrcode/swervo/internal/utils"
awsidc "github.com/abjrcode/swervo/providers/aws_idc"
awscredentialsfile "github.com/abjrcode/swervo/sinks/aws_credentials_file"
awscredssink "github.com/abjrcode/swervo/sinks/awscredssink"
"github.com/rs/zerolog"
"github.com/wailsapp/wails/v2/pkg/menu"
"github.com/wailsapp/wails/v2/pkg/menu/keys"
Expand All @@ -33,7 +33,7 @@ type AppController struct {

awsIdcController *awsidc.AwsIdentityCenterController

awsCredentialsFileSinkController *awscredentialsfile.AwsCredentialsFileSinkController
awsCredentialsSinkController *awscredssink.AwsCredentialsSinkController
}

func (c *AppController) init(ctx context.Context, errorHandler app.ErrorHandler) {
Expand Down Expand Up @@ -145,13 +145,21 @@ func (c *AppController) RunAppCommand(command string, commandInput map[string]an
output, err = c.awsIdcController.GetInstanceData(appContext,
commandInput["instanceId"].(string),
commandInput["forceRefresh"].(bool))
case "AwsIdc_GetRoleCredentials":
output, err = c.awsIdcController.GetRoleCredentials(appContext,
awsidc.AwsIdc_GetRoleCredentialsCommandInput{
case "AwsIdc_CopyRoleCredentials":
err = c.awsIdcController.CopyRoleCredentials(appContext,
awsidc.AwsIdc_CopyRoleCredentialsCommandInput{
InstanceId: commandInput["instanceId"].(string),
AccountId: commandInput["accountId"].(string),
RoleName: commandInput["roleName"].(string),
})
case "AwsIdc_SaveRoleCredentials":
err = c.awsIdcController.SaveRoleCredentials(appContext,
awsidc.AwsIdc_SaveRoleCredentialsCommandInput{
InstanceId: commandInput["instanceId"].(string),
AccountId: commandInput["accountId"].(string),
RoleName: commandInput["roleName"].(string),
AwsProfile: commandInput["awsProfile"].(string),
})
case "AwsIdc_Setup":
output, err = c.awsIdcController.Setup(appContext,
awsidc.AwsIdc_SetupCommandInput{
Expand Down Expand Up @@ -183,21 +191,21 @@ func (c *AppController) RunAppCommand(command string, commandInput map[string]an
UserCode: commandInput["userCode"].(string),
DeviceCode: commandInput["deviceCode"].(string),
})
case "AwsCredentialsFile_NewInstance":
output, err = c.awsCredentialsFileSinkController.NewInstance(appContext,
awscredentialsfile.AwsCredentialsFile_NewInstanceCommandInput{
case "AwsCredentialsSink_NewInstance":
output, err = c.awsCredentialsSinkController.NewInstance(appContext,
awscredssink.AwsCredentialsSink_NewInstanceCommandInput{
FilePath: commandInput["filePath"].(string),
AwsProfileName: commandInput["awsProfileName"].(string),
Label: commandInput["label"].(string),
ProviderCode: commandInput["providerCode"].(string),
ProviderId: commandInput["providerId"].(string),
})
case "AwsCredentialsFile_GetInstanceData":
output, err = c.awsCredentialsFileSinkController.GetInstanceData(appContext,
case "AwsCredentialsSink_GetInstanceData":
output, err = c.awsCredentialsSinkController.GetInstanceData(appContext,
commandInput["instanceId"].(string),
)
case "AwsCredentialsFile_DisconnectSink":
err = c.awsCredentialsFileSinkController.DisconnectSink(appContext, plumbing.DisconnectSinkCommandInput{
case "AwsCredentialsSink_DisconnectSink":
err = c.awsCredentialsSinkController.DisconnectSink(appContext, plumbing.DisconnectSinkCommandInput{
SinkCode: commandInput["sinkCode"].(string),
SinkId: commandInput["sinkId"].(string),
})
Expand Down
152 changes: 152 additions & 0 deletions clients/awscredsfile/aws_creds_file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
package awscredsfile

import (
"fmt"
"io"
"os"
"slices"
"strings"

"github.com/abjrcode/swervo/internal/app"
"github.com/abjrcode/swervo/internal/utils"
"github.com/aws/aws-sdk-go-v2/config"
)

var (
ErrInvalidCredentialsFile = app.NewValidationError("INVALID_CREDENTIALS_FILE")
ErrEmptyProfile = app.NewValidationError("EMPTY_PROFILE")
ErrEmptyKey = app.NewValidationError("EMPTY_KEY")
ErrEmptyKeyValue = app.NewValidationError("EMPTY_KEY_VALUE")
)

type credentialsFileManager struct {
filePath string
}

func NewCredentialsFileManager(filePath string) *credentialsFileManager {
return &credentialsFileManager{
filePath: filePath,
}
}

func NewDefaultCredentialsFileManager() *credentialsFileManager {
return NewCredentialsFileManager(config.DefaultSharedCredentialsFilename())
}

type ProfileCreds struct {
AwsAccessKeyId string
AwsSecretAccessKey string
AwsSessionToken *string
}

func (manager *credentialsFileManager) WriteProfileCredentials(profileName string, creds ProfileCreds) error {
credFilePath := manager.filePath

fileWasCreated := false

var file *os.File

if _, err := os.Stat(credFilePath); os.IsNotExist(err) {
file, err = os.Create(credFilePath)
fileWasCreated = true

if err != nil {
return err
}
} else {
file, err = os.OpenFile(credFilePath, os.O_RDWR, 0644)
if err != nil {
return err
}
}

defer file.Close()

if fileWasCreated {
var builder strings.Builder

builder.WriteString(fmt.Sprintf("[%s]\n", profileName))
builder.WriteString(fmt.Sprintf("aws_access_key_id = %s\n", creds.AwsAccessKeyId))
builder.WriteString(fmt.Sprintf("aws_secret_access_key = %s\n", creds.AwsSecretAccessKey))

if creds.AwsSessionToken != nil {
builder.WriteString(fmt.Sprintf("aws_session_token = %s\n", *creds.AwsSessionToken))
}

credentialsProfile := builder.String()

_, err := file.WriteString(credentialsProfile)

if err != nil {
return err
}
} else {
credentialsProfile, err := io.ReadAll(file)

if err != nil {
return err
}

parser := newParser(string(credentialsProfile))
credentials, err := parser.parse()

if err != nil {
return err
}

index := slices.IndexFunc(credentials, func(cred profileCredentials) bool {
return cred.Profile == profileName
})

if index == -1 {
credentials = append(credentials, profileCredentials{
Profile: profileName,
AccessKeyID: creds.AwsAccessKeyId,
SecretAccessKey: creds.AwsSecretAccessKey,
SessionToken: creds.AwsSessionToken,
})
} else {
credentials[index].AccessKeyID = creds.AwsAccessKeyId
credentials[index].SecretAccessKey = creds.AwsSecretAccessKey
credentials[index].SessionToken = creds.AwsSessionToken
}

if err != nil {
return err
}

err = file.Close()

if err != nil {
return err
}

err = utils.SafelyOverwriteFile(file.Name(), serializeCredentialsToString(credentials))

if err != nil {
return err
}
}

return nil
}

func serializeCredentialsToString(credentials []profileCredentials) string {
var result strings.Builder

for _, cred := range credentials {
result.WriteString(fmt.Sprintf("[%s]\n", cred.Profile))

result.WriteString(fmt.Sprintf("aws_access_key_id = %s\n", cred.AccessKeyID))

result.WriteString(fmt.Sprintf("aws_secret_access_key = %s\n", cred.SecretAccessKey))

if cred.SessionToken != nil {
result.WriteString(fmt.Sprintf("aws_session_token = %s\n", *cred.SessionToken))
}

result.WriteString("\n")
}

return result.String()
}
Loading

0 comments on commit 310069c

Please sign in to comment.