89 lines
2.4 KiB
Go
89 lines
2.4 KiB
Go
package main
|
|||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"data-terminal-cloud/internal/onboarding"
|
||
|
|
"encoding/json"
|
||
|
|
"errors"
|
||
|
|
"fmt"
|
||
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
||
|
|
"github.com/redis/go-redis/v9"
|
||
|
|
"io"
|
||
|
|
"os"
|
||
|
|
"strings"
|
||
|
|
"time"
|
||
|
|
)
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
if err := run(); err != nil {
|
||
|
|
fmt.Fprintln(os.Stderr, err)
|
||
|
|
os.Exit(1)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
func secret(name string) (string, error) {
|
||
|
|
if file := os.Getenv(name + "_FILE"); file != "" {
|
||
|
|
b, e := os.ReadFile(file)
|
||
|
|
if e != nil {
|
||
|
|
return "", fmt.Errorf("read %s_FILE: %w", name, e)
|
||
|
|
}
|
||
|
|
return strings.TrimSpace(string(b)), nil
|
||
|
|
}
|
||
|
|
if v := os.Getenv(name); v != "" {
|
||
|
|
return v, nil
|
||
|
|
}
|
||
|
|
return "", fmt.Errorf("missing %s", name)
|
||
|
|
}
|
||
|
|
func run() error {
|
||
|
|
if len(os.Args) != 1 {
|
||
|
|
return errors.New("customer-phone-account reads provisioning JSON from standard input")
|
||
|
|
}
|
||
|
|
var in struct {
|
||
|
|
AccountKind string `json:"account_kind"`
|
||
|
|
UserID string `json:"user_id"`
|
||
|
|
Issuer string `json:"issuer"`
|
||
|
|
Subject string `json:"subject"`
|
||
|
|
Phone string `json:"phone_e164"`
|
||
|
|
Password string `json:"password"`
|
||
|
|
RequestID string `json:"request_id"`
|
||
|
|
}
|
||
|
|
raw, err := io.ReadAll(io.LimitReader(os.Stdin, 8193))
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
if err = onboarding.StrictJSON(raw, &in); err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
db, err := secret("DATABASE_URL")
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
master, err := secret("ONBOARDING_MASTER_KEY")
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||
|
|
defer cancel()
|
||
|
|
pool, err := pgxpool.New(ctx, db)
|
||
|
|
if err != nil {
|
||
|
|
return errors.New("database configuration invalid")
|
||
|
|
}
|
||
|
|
defer pool.Close()
|
||
|
|
r := redis.NewClient(&redis.Options{Addr: os.Getenv("REDIS_ADDR")})
|
||
|
|
defer r.Close()
|
||
|
|
s, err := onboarding.NewService(pool, r, onboarding.Options{MasterKey: master, EntryURL: os.Getenv("ONBOARDING_ENTRY_URL")})
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
provision := s.ProvisionCustomerPhone
|
||
|
|
if in.AccountKind == "operator" {
|
||
|
|
provision = s.ProvisionOperatorPhone
|
||
|
|
} else if in.AccountKind != "" && in.AccountKind != "customer" {
|
||
|
|
return errors.New("invalid account_kind")
|
||
|
|
}
|
||
|
|
created, err := provision(ctx, in.UserID, in.Issuer, in.Subject, in.Phone, in.Password, in.RequestID)
|
||
|
|
if err != nil {
|
||
|
|
return err
|
||
|
|
}
|
||
|
|
return json.NewEncoder(os.Stdout).Encode(map[string]any{"configured": true, "created": created, "user_id": in.UserID, "phone_masked": in.Phone[:len(in.Phone)-8] + "****" + in.Phone[len(in.Phone)-4:], "sms_verified": false})
|
||
|
|
}
|