Authorize consents for the account-holder type the bank supports
Kontist authorized but shared no accounts: psu_type was hardcoded to personal, and Enable Banking documents that a psu_type mismatch can yield a consent without the expected accounts. The bank listing now reports each institution's supported psu_types, the connect form offers only those, the chosen type reaches POST /auth, and an unsupported combination is refused before the user is sent to a bank. The choice is stored per consent so reconnecting reuses it; consents predating the choice stay personal. Also repairs the frontend derivation, which the Montserrat dependency broke: npmDepsHash was stale and web/public was missing from the fileset, so the traced duck icon never reached the built assets.
This commit is contained in:
+20
-6
@@ -174,7 +174,10 @@ func (a *App) Backfill(ctx context.Context, rev, accountID string, historyMonths
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
func (a *App) Authorize(ctx context.Context, institution, country string, historyMonths int) (string, error) {
|
||||
|
||||
// Authorize starts a consent for one account-holder kind. An empty psuType
|
||||
// keeps the previous personal default for existing API callers.
|
||||
func (a *App) Authorize(ctx context.Context, institution, country, psuType string, historyMonths int) (string, error) {
|
||||
a.mu.Lock()
|
||||
defer a.mu.Unlock()
|
||||
if historyMonths < 1 || historyMonths > 120 {
|
||||
@@ -191,17 +194,24 @@ func (a *App) Authorize(ctx context.Context, institution, country string, histor
|
||||
if len(country) != 2 {
|
||||
return "", errors.New("country must be a two-letter code")
|
||||
}
|
||||
if psuType == "" {
|
||||
psuType = banking.PSUPersonal
|
||||
}
|
||||
if !banking.ValidPSUType(psuType) {
|
||||
return "", errors.New("account type must be personal or business")
|
||||
}
|
||||
for state, auth := range a.authStates {
|
||||
if time.Now().After(auth.Expires) {
|
||||
delete(a.authStates, state)
|
||||
}
|
||||
}
|
||||
state := domain.NewID("auth")
|
||||
url, err := a.bank.Authorize(ctx, institution, country, state)
|
||||
if err == nil {
|
||||
a.authStates[state] = authorization{Expires: time.Now().Add(15 * time.Minute), Institution: institution, Country: country, HistoryMonths: historyMonths}
|
||||
url, err := a.bank.Authorize(ctx, institution, country, psuType, state)
|
||||
if err != nil {
|
||||
return "", bankFailure(err, "bank authorization unavailable; retry connecting")
|
||||
}
|
||||
return url, err
|
||||
a.authStates[state] = authorization{Expires: time.Now().Add(15 * time.Minute), Institution: institution, Country: country, PSUType: psuType, HistoryMonths: historyMonths}
|
||||
return url, nil
|
||||
}
|
||||
|
||||
// Institutions lists connectable banks for the country so the UI can offer
|
||||
@@ -276,7 +286,7 @@ func (a *App) Callback(ctx context.Context, code, state string) (int, error) {
|
||||
return 0, errors.New("the bank authorized the connection but shared no accounts, so nothing was linked; accounts of another type (for example business) may need a separate consent")
|
||||
}
|
||||
a.ops.Sessions = append(a.ops.Sessions, session)
|
||||
a.ops.Consents[session.ID] = Consent{Institution: auth.Institution, Country: auth.Country, HistoryMonths: auth.HistoryMonths}
|
||||
a.ops.Consents[session.ID] = Consent{Institution: auth.Institution, Country: auth.Country, PSUType: auth.PSUType, HistoryMonths: auth.HistoryMonths}
|
||||
if err = a.saveOps(); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -359,6 +369,10 @@ func bankFailure(err error, fallback string) error {
|
||||
if errors.As(err, &api) {
|
||||
return api
|
||||
}
|
||||
var consent *banking.ConsentError
|
||||
if errors.As(err, &consent) {
|
||||
return consent
|
||||
}
|
||||
return errors.New(fallback)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user