Documentation
¶
Index ¶
- Constants
- Variables
- func IsSecretLikeName(name string) bool
- func Query(db *datastore.Datastore) datastore.Query
- type ByName
- type Organization
- func (o *Organization) AddAdmin(userOrId string)
- func (o *Organization) AddDefaultTokens()
- func (o *Organization) AddOwner(userOrId string)
- func (o *Organization) AfterCreate() error
- func (o Organization) AuthorizeNetToken(sandbox bool) integration.AuthorizeNetConnection
- func (o *Organization) BeforeCreate() error
- func (o *Organization) Defaults()
- func (o Organization) GetDefaultApp() (*app.App, error)
- func (o Organization) GetDefaultStore() (*store.Store, error)
- func (o *Organization) GetReferenceToken(usr *user.User) (*oauthtoken.Token, bool, error)
- func (o Organization) GetStripeAccessToken(userId string) (string, error)
- func (o *Organization) Init(db *datastore.Datastore)
- func (o Organization) IsAdmin(userOrId interface{}) bool
- func (o Organization) IsOwner(userOrId interface{}) bool
- func (o Organization) IsTestEmail(email string) bool
- func (o *Organization) Load(ps []datastore.Property) (err error)
- func (o Organization) Namespace() string
- func (o Organization) Namespaced(ctx context.Context) context.Context
- func (o Organization) Pricing() (*pricing.Fees, []pricing.Partner)
- func (o *Organization) ResetReferenceToken(usr *user.User, claims oauthtoken.Claims) (*oauthtoken.Token, error)
- func (o *Organization) RevokeReferenceToken(usr *user.User) (*oauthtoken.Token, bool, error)
- func (o *Organization) Save() (ps []datastore.Property, err error)
- func (o Organization) SquareConfig(sandbox bool) integration.SquareConnection
- func (o Organization) SquareEnvironment() string
- func (o Organization) StripeToken() string
- func (o Organization) TestMode() bool
- func (o *Organization) Validator() *val.Validator
- type StripeAccessTokenNotFound
Constants ¶
const ( DefaultAppName = "Hanzo App" DefaultStoreName = "Default" )
Variables ¶
var ErrSecretLikeName = errors.New("organization: refusing to provision org from a bearer-shaped name")
ErrSecretLikeName is returned when an untrusted, gateway-supplied org name is actually a raw API key / bearer token rather than a real org identifier.
var (
UserNotTopLevel = errors.New("User is not in the top level namespace.")
)
Functions ¶
func IsSecretLikeName ¶
IsSecretLikeName reports whether an org identifier looks like a raw API key / bearer token rather than a real organization slug. Real orgs are short slugs ("hanzo", "adnexus"), UUIDs, or numeric ids; leaked provider keys carry a recognizable prefix — Anthropic (sk-ant-), OpenAI (sk-proj-), DigitalOcean (sk-do-), and Hanzo (sk-hz- / hk-).
Any code that provisions an org via GetOrCreate from an untrusted, gateway-supplied name MUST reject these first: otherwise a caller who presents a raw key as their bearer causes the key to be persisted as an org name and tenant id, leaking the secret into the datastore (incident 2026-07-02). This mirrors the DB backstop trigger trg_reject_bearer_tenant on _entities.
The check is intentionally prefix-based (matching the DB trigger) so it never rejects a real slug: "skunkworks" and "hkust" do not start with "sk-"/"hk-".
Types ¶
type ByName ¶
type ByName []*Organization
type Organization ¶
type Organization struct {
mixin.Model[Organization]
mixin.AccessTokens
wallet.WalletHolder
Name string `json:"name"`
FullName string `json:"fullName"`
Owners []string `json:"owners,omitempty" datastore:",noindex"`
Admins []string `json:"admins,omitempty" datastore:",noindex"`
Moderators []string `json:"moderators,omitempty" datastore:",noindex"`
Enabled bool `json:"enabled"`
BillingEmail string `json:"billingEmail,omitempty"`
Phone string `json:"phone,omitempty"`
Address Address `json:"address,omitempty"`
SocialMedia socialmedia.SocialMedia `json:"socialMedia,omitEmpty"`
Websites []website.Website `json:"websites,omitEmpty"`
WalletPassphrase string `json:"-"`
Timezone string `json:"timezone"`
Country string `json:"country"`
TaxId string `json:"taxId"`
// Used in generating email templates
LogoUrl string `json:"logoUrl"`
// Where is the user's dashboard?
DashboardUrl string `json:"dashboardUrl"`
// Fee structure for this organization
Fees pricing.Fees `json:"fees" datastore:",noindex"`
// Partner fees (private, should be up to partner to disclose)
Partners []pricing.Partner `json:"-" datastore:",noindex"`
// Email settings
Email email.Settings `json:"email" datastore:",noindex"`
// Default Store
DefaultStore string `json:"defaultStore"`
// Default App
DefaultApp string `json:"defaultApp"`
// Plan settings
Plan struct {
PlanId string
StartDate time.Time
} `json:"-"`
// Affiliate configuration
Affiliate integration.Affiliate `json:"-" datastore:",noindex"`
// Signup options
SignUpOptions struct {
// Controls the enabled status of account after creation
AccountsEnabledByDefault bool `json:"accountsEnabledByDefault"`
// Allow direct affiliate sign up
AllowAffiliateSignup bool `json:"allowAffiliateSignup"`
// Turns off required backend checks
NoNameRequired bool `json:"noNameRequired"`
NoPasswordRequired bool `json:"noPasswordRequired"`
// Requires password set on create confirmation
TwoStageEnabled bool `json:"twoStageEnabled"`
ImmediateLogin bool `json:"immediateLogin"`
UsernameRequired bool `json:"usernameRequired"`
} `json:"signUpOptions" datastore:",noindex"`
// Whether we use live or test tokens, mostly applicable to stripe
Live bool `json:"live"`
// TODO: Remain to PaymentWhitelist for clarity
// List of comma deliminated email globs that result in charges of 50 cents
EmailWhitelist string `json:"emailWhitelist" datastore:",noindex"`
// integration
Integrations integration.Integrations `json:"-" datastore:"-"`
Integrations_ string `json:"-" datastore:",noindex"`
// Analytics config
Analytics analytics.Analytics `json:"analytics" datastore:",noindex"`
// Bitcoi settings
Bitcoin integration.Bitcoin `json:"-"`
// Ethereum settings
Ethereum integration.Ethereum `json:"-"`
// Mailchimp settings
Mailchimp integration.Mailchimp `json:"-"`
// Mandrill settings
Mandrill integration.Mandrill `json:"-"`
// Mercury bank connection
Mercury integration.Mercury `json:"-"`
// Netlify settings
Netlify integration.Netlify `json:"-"`
// Paypal connection
Paypal integration.Paypal `json:"-"`
// Plaid connection
Plaid integration.Plaid `json:"-"`
// ReAmaze settings
Reamaze integration.Reamaze `json:"-"`
Recaptcha integration.Recaptcha `json:"-" datastore:",noindex"`
// Salesforce settings
Salesforce integration.Salesforce `json:"-"`
// Shipwire settings
Shipwire integration.Shipwire `json:"-"`
// Square connection
Square integration.Square `json:"-"`
// Stripe connection
Stripe integration.Stripe `json:"-"`
// Wire transfer settings
Wire integration.WireTransfer `json:"-"`
// AuthorizeNet connection
AuthorizeNet integration.AuthorizeNet `json:"-"`
// Adyen connection
Adyen integration.Adyen `json:"-"`
// Braintree connection
Braintree integration.Braintree `json:"-"`
// Recurly connection
Recurly integration.Recurly `json:"-"`
// LemonSqueezy connection
LemonSqueezy integration.LemonSqueezy `json:"-"`
SecurityToken integration.SecurityToken `json:"-"`
Currency currency.Type `json:"currency"`
}
func New ¶
func New(db *datastore.Datastore) *Organization
func (*Organization) AddAdmin ¶
func (o *Organization) AddAdmin(userOrId string)
Add admin to organization
func (*Organization) AddDefaultTokens ¶
func (o *Organization) AddDefaultTokens()
Old JWT / AccessToken AUTH
func (*Organization) AddOwner ¶
func (o *Organization) AddOwner(userOrId string)
Add admin to organization
func (*Organization) AfterCreate ¶
func (o *Organization) AfterCreate() error
func (Organization) AuthorizeNetToken ¶
func (o Organization) AuthorizeNetToken(sandbox bool) integration.AuthorizeNetConnection
func (*Organization) Defaults ¶
func (o *Organization) Defaults()
func (Organization) GetDefaultApp ¶
func (o Organization) GetDefaultApp() (*app.App, error)
Return DefaultApp
func (Organization) GetDefaultStore ¶
func (o Organization) GetDefaultStore() (*store.Store, error)
Return DefaultStore
func (*Organization) GetReferenceToken ¶
func (o *Organization) GetReferenceToken(usr *user.User) (*oauthtoken.Token, bool, error)
func (Organization) GetStripeAccessToken ¶
func (o Organization) GetStripeAccessToken(userId string) (string, error)
func (*Organization) Init ¶
func (o *Organization) Init(db *datastore.Datastore)
func (Organization) IsAdmin ¶
func (o Organization) IsAdmin(userOrId interface{}) bool
func (Organization) IsOwner ¶
func (o Organization) IsOwner(userOrId interface{}) bool
func (Organization) IsTestEmail ¶
func (o Organization) IsTestEmail(email string) bool
func (Organization) Namespace ¶
func (o Organization) Namespace() string
Namespace returns the datastore namespace for this organization.
SECURITY: every org — without exception — is strictly scoped to its own name. There is NO org-name escape hatch. The legacy `Name=="platform" -> "" (global/cross-org namespace)` bypass was REMOVED: it keyed cross-org datastore access on an org-NAME string, fully decoupled from real platform-admin identity, so anyone who could land in (or forge) an org named "platform" read/wrote the global namespace where every org's records live (Red — privilege escalation via the empty namespace). Cross-org / superadmin datastore access is now gated EXCLUSIVELY on auth.IAMClaims.IsSuperAdmin() (owner=="admin") at the handler/middleware layer — never inferred from the org name here.
func (Organization) Namespaced ¶
func (o Organization) Namespaced(ctx context.Context) context.Context
Namespaced returns a context scoped to this organization's namespace. When called with a gin.Context, we always detach from the HTTP request lifecycle and use context.Background() for the database context. This prevents "context canceled" errors when the browser disconnects or the upstream proxy timeout fires before the datastore query completes.
func (*Organization) ResetReferenceToken ¶
func (o *Organization) ResetReferenceToken(usr *user.User, claims oauthtoken.Claims) (*oauthtoken.Token, error)
New JWT / OAUTH
func (*Organization) RevokeReferenceToken ¶
func (o *Organization) RevokeReferenceToken(usr *user.User) (*oauthtoken.Token, bool, error)
func (Organization) SquareConfig ¶
func (o Organization) SquareConfig(sandbox bool) integration.SquareConnection
func (Organization) SquareEnvironment ¶
func (o Organization) SquareEnvironment() string
SquareEnvironment returns "sandbox" or "production" — the value the Square SDK uses to select its API base URL — derived from TestMode (one authority).
func (Organization) StripeToken ¶
func (o Organization) StripeToken() string
func (Organization) TestMode ¶
func (o Organization) TestMode() bool
TestMode reports whether this org transacts in TEST mode on the current deployment. It is the SINGLE authority for BOTH the payment environment (Square sandbox vs production) AND the ledger (trans.Test, balance bucket, pay.Live). Keeping the charge environment and the ledger on ONE authority is what prevents a sandbox charge from crediting the live (spendable) balance and a production charge from booking test (unbilled) revenue.
SQUARE_ENVIRONMENT is the deployment authority and makes the 3-env split pure per-env config (mainnet=production, testnet/devnet=sandbox). It is fail-CLOSED: only an explicit, recognized "production" (or prod/live) selects production; anything else that is SET — sandbox/test, an empty placeholder, or a typo — selects test/sandbox, so a misconfiguration can never silently charge real cards. When SQUARE_ENVIRONMENT is UNSET, the org's own live flag decides (live→production, test→sandbox) so local and un-templated deploys still resolve.
func (*Organization) Validator ¶
func (o *Organization) Validator() *val.Validator
type StripeAccessTokenNotFound ¶
func (StripeAccessTokenNotFound) Error ¶
func (e StripeAccessTokenNotFound) Error() string