ente/cli/pkg/sync_authenticator.go
2024-09-18 17:36:24 +05:30

110 lines
2.9 KiB
Go

package pkg
import (
"context"
"encoding/base64"
"fmt"
"github.com/ente-io/cli/internal/api/models"
"github.com/ente-io/cli/pkg/mapper"
"github.com/ente-io/cli/pkg/model"
"log"
"os"
"time"
)
func (c *ClICtrl) SyncAuthAccount(account model.Account, filters model.Filter) error {
secretInfo, err := c.KeyHolder.LoadSecrets(account)
if err != nil {
return err
}
ctx := c.buildRequestContext(context.Background(), account, filters)
err = createDataBuckets(c.DB, account)
if err != nil {
return err
}
c.Client.AddToken(account.AccountKey(), base64.URLEncoding.EncodeToString(secretInfo.Token))
data, err := c.fetchRemoteAuthenticatorData(ctx)
if err != nil {
log.Printf("Error fetching entities: %s", err)
return err
}
return c.writeAuthExport(ctx, account, data)
}
func (c *ClICtrl) writeAuthExport(ctx context.Context, account model.Account, data []string) error {
exportDir := account.ExportDir
if exportDir == "" {
return fmt.Errorf("export directory not set")
}
outputFile := fmt.Sprintf("%s/ente_auth.txt", exportDir)
// if outout file exists, create a backup with current datetime
if _, err := os.Stat(outputFile); err == nil {
backupFile := fmt.Sprintf("%s/ente_auth_%s.txt", exportDir, time.Now().Format("2006-01-02_15-04-05"))
if err := os.Rename(outputFile, backupFile); err != nil {
return fmt.Errorf("error creating backup file: %v", err)
}
}
// write the data to the output file, one line per entity
file, err := os.Create(outputFile)
if err != nil {
return fmt.Errorf("error creating output file: %v", err)
}
defer file.Close()
for _, line := range data {
if _, err := file.WriteString(line + "\n"); err != nil {
return fmt.Errorf("error writing to output file: %v", err)
}
}
return nil
}
func (c *ClICtrl) fetchRemoteAuthenticatorData(ctx context.Context) ([]string, error) {
var entities []models.AuthEntity
hasMore := true
sinceTime := int64(0)
for hasMore {
fetched, err := c.Client.GetAuthDiff(ctx, sinceTime, 500)
if err != nil {
return nil, fmt.Errorf("failed to get entities: %s", err)
}
entities = append(entities, fetched...)
if len(fetched) < 500 {
hasMore = false
} else {
for _, entity := range fetched {
if entity.UpdatedAt > sinceTime {
sinceTime = entity.UpdatedAt
}
}
}
}
if len(entities) == 0 {
log.Println("No data to export")
return nil, nil
}
var key []byte
var err error
authKey, authKeyErr := c.Client.GetAuthKey(ctx)
if authKeyErr != nil {
return nil, fmt.Errorf("failed to get auth key: %s", authKeyErr)
} else {
key, err = c.KeyHolder.GetAuthenticatorKey(ctx, *authKey)
if err != nil {
return nil, fmt.Errorf("failed to decrypt auth key: %s", err)
}
}
var codes []string
for _, authEntity := range entities {
if authEntity.IsDeleted {
continue
}
code, mapErr := mapper.MapRemoteAuthEntityToString(ctx, authEntity, key)
if mapErr != nil {
return nil, mapErr
}
codes = append(codes, *code)
}
return codes, nil
}