[#275] added support to customize the default user email templates from the Admin UI
This commit is contained in:
parent
1de56d3d9e
commit
7d10d20de1
212
core/settings.go
212
core/settings.go
|
@ -10,48 +10,46 @@ import (
|
||||||
validation "github.com/go-ozzo/ozzo-validation/v4"
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
"github.com/go-ozzo/ozzo-validation/v4/is"
|
"github.com/go-ozzo/ozzo-validation/v4/is"
|
||||||
"github.com/pocketbase/pocketbase/tools/auth"
|
"github.com/pocketbase/pocketbase/tools/auth"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/rest"
|
||||||
"github.com/pocketbase/pocketbase/tools/security"
|
"github.com/pocketbase/pocketbase/tools/security"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Common settings placeholder tokens
|
|
||||||
const (
|
|
||||||
EmailPlaceholderAppUrl string = "%APP_URL%"
|
|
||||||
EmailPlaceholderToken string = "%TOKEN%"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Settings defines common app configuration options.
|
// Settings defines common app configuration options.
|
||||||
type Settings struct {
|
type Settings struct {
|
||||||
mux sync.RWMutex
|
mux sync.RWMutex
|
||||||
|
|
||||||
Meta MetaConfig `form:"meta" json:"meta"`
|
Meta MetaConfig `form:"meta" json:"meta"`
|
||||||
Logs LogsConfig `form:"logs" json:"logs"`
|
Logs LogsConfig `form:"logs" json:"logs"`
|
||||||
Smtp SmtpConfig `form:"smtp" json:"smtp"`
|
Smtp SmtpConfig `form:"smtp" json:"smtp"`
|
||||||
S3 S3Config `form:"s3" json:"s3"`
|
S3 S3Config `form:"s3" json:"s3"`
|
||||||
AdminAuthToken TokenConfig `form:"adminAuthToken" json:"adminAuthToken"`
|
|
||||||
AdminPasswordResetToken TokenConfig `form:"adminPasswordResetToken" json:"adminPasswordResetToken"`
|
AdminAuthToken TokenConfig `form:"adminAuthToken" json:"adminAuthToken"`
|
||||||
UserAuthToken TokenConfig `form:"userAuthToken" json:"userAuthToken"`
|
AdminPasswordResetToken TokenConfig `form:"adminPasswordResetToken" json:"adminPasswordResetToken"`
|
||||||
UserPasswordResetToken TokenConfig `form:"userPasswordResetToken" json:"userPasswordResetToken"`
|
UserAuthToken TokenConfig `form:"userAuthToken" json:"userAuthToken"`
|
||||||
UserEmailChangeToken TokenConfig `form:"userEmailChangeToken" json:"userEmailChangeToken"`
|
UserPasswordResetToken TokenConfig `form:"userPasswordResetToken" json:"userPasswordResetToken"`
|
||||||
UserVerificationToken TokenConfig `form:"userVerificationToken" json:"userVerificationToken"`
|
UserEmailChangeToken TokenConfig `form:"userEmailChangeToken" json:"userEmailChangeToken"`
|
||||||
EmailAuth EmailAuthConfig `form:"emailAuth" json:"emailAuth"`
|
UserVerificationToken TokenConfig `form:"userVerificationToken" json:"userVerificationToken"`
|
||||||
GoogleAuth AuthProviderConfig `form:"googleAuth" json:"googleAuth"`
|
|
||||||
FacebookAuth AuthProviderConfig `form:"facebookAuth" json:"facebookAuth"`
|
EmailAuth EmailAuthConfig `form:"emailAuth" json:"emailAuth"`
|
||||||
GithubAuth AuthProviderConfig `form:"githubAuth" json:"githubAuth"`
|
GoogleAuth AuthProviderConfig `form:"googleAuth" json:"googleAuth"`
|
||||||
GitlabAuth AuthProviderConfig `form:"gitlabAuth" json:"gitlabAuth"`
|
FacebookAuth AuthProviderConfig `form:"facebookAuth" json:"facebookAuth"`
|
||||||
|
GithubAuth AuthProviderConfig `form:"githubAuth" json:"githubAuth"`
|
||||||
|
GitlabAuth AuthProviderConfig `form:"gitlabAuth" json:"gitlabAuth"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewSettings creates and returns a new default Settings instance.
|
// NewSettings creates and returns a new default Settings instance.
|
||||||
func NewSettings() *Settings {
|
func NewSettings() *Settings {
|
||||||
return &Settings{
|
return &Settings{
|
||||||
Meta: MetaConfig{
|
Meta: MetaConfig{
|
||||||
AppName: "Acme",
|
AppName: "Acme",
|
||||||
AppUrl: "http://localhost:8090",
|
AppUrl: "http://localhost:8090",
|
||||||
SenderName: "Support",
|
SenderName: "Support",
|
||||||
SenderAddress: "support@example.com",
|
SenderAddress: "support@example.com",
|
||||||
UserVerificationUrl: EmailPlaceholderAppUrl + "/_/#/users/confirm-verification/" + EmailPlaceholderToken,
|
VerificationTemplate: defaultVerificationTemplate,
|
||||||
UserResetPasswordUrl: EmailPlaceholderAppUrl + "/_/#/users/confirm-password-reset/" + EmailPlaceholderToken,
|
ResetPasswordTemplate: defaultResetPasswordTemplate,
|
||||||
UserConfirmEmailChangeUrl: EmailPlaceholderAppUrl + "/_/#/users/confirm-email-change/" + EmailPlaceholderToken,
|
ConfirmEmailChangeTemplate: defaultConfirmEmailChangeTemplate,
|
||||||
},
|
},
|
||||||
|
|
||||||
Logs: LogsConfig{
|
Logs: LogsConfig{
|
||||||
MaxDays: 7,
|
MaxDays: 7,
|
||||||
},
|
},
|
||||||
|
@ -194,6 +192,9 @@ func (s *Settings) RedactClone() (*Settings, error) {
|
||||||
// NamedAuthProviderConfigs returns a map with all registered OAuth2
|
// NamedAuthProviderConfigs returns a map with all registered OAuth2
|
||||||
// provider configurations (indexed by their name identifier).
|
// provider configurations (indexed by their name identifier).
|
||||||
func (s *Settings) NamedAuthProviderConfigs() map[string]AuthProviderConfig {
|
func (s *Settings) NamedAuthProviderConfigs() map[string]AuthProviderConfig {
|
||||||
|
s.mux.RLock()
|
||||||
|
defer s.mux.RUnlock()
|
||||||
|
|
||||||
return map[string]AuthProviderConfig{
|
return map[string]AuthProviderConfig{
|
||||||
auth.NameGoogle: s.GoogleAuth,
|
auth.NameGoogle: s.GoogleAuth,
|
||||||
auth.NameFacebook: s.FacebookAuth,
|
auth.NameFacebook: s.FacebookAuth,
|
||||||
|
@ -267,13 +268,13 @@ func (c S3Config) Validate() error {
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
type MetaConfig struct {
|
type MetaConfig struct {
|
||||||
AppName string `form:"appName" json:"appName"`
|
AppName string `form:"appName" json:"appName"`
|
||||||
AppUrl string `form:"appUrl" json:"appUrl"`
|
AppUrl string `form:"appUrl" json:"appUrl"`
|
||||||
SenderName string `form:"senderName" json:"senderName"`
|
SenderName string `form:"senderName" json:"senderName"`
|
||||||
SenderAddress string `form:"senderAddress" json:"senderAddress"`
|
SenderAddress string `form:"senderAddress" json:"senderAddress"`
|
||||||
UserVerificationUrl string `form:"userVerificationUrl" json:"userVerificationUrl"`
|
VerificationTemplate EmailTemplate `form:"verificationTemplate" json:"verificationTemplate"`
|
||||||
UserResetPasswordUrl string `form:"userResetPasswordUrl" json:"userResetPasswordUrl"`
|
ResetPasswordTemplate EmailTemplate `form:"resetPasswordTemplate" json:"resetPasswordTemplate"`
|
||||||
UserConfirmEmailChangeUrl string `form:"userConfirmEmailChangeUrl" json:"userConfirmEmailChangeUrl"`
|
ConfirmEmailChangeTemplate EmailTemplate `form:"confirmEmailChangeTemplate" json:"confirmEmailChangeTemplate"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate makes MetaConfig validatable by implementing [validation.Validatable] interface.
|
// Validate makes MetaConfig validatable by implementing [validation.Validatable] interface.
|
||||||
|
@ -283,34 +284,45 @@ func (c MetaConfig) Validate() error {
|
||||||
validation.Field(&c.AppUrl, validation.Required, is.URL),
|
validation.Field(&c.AppUrl, validation.Required, is.URL),
|
||||||
validation.Field(&c.SenderName, validation.Required, validation.Length(1, 255)),
|
validation.Field(&c.SenderName, validation.Required, validation.Length(1, 255)),
|
||||||
validation.Field(&c.SenderAddress, is.Email, validation.Required),
|
validation.Field(&c.SenderAddress, is.Email, validation.Required),
|
||||||
|
validation.Field(&c.VerificationTemplate, validation.Required),
|
||||||
|
validation.Field(&c.ResetPasswordTemplate, validation.Required),
|
||||||
|
validation.Field(&c.ConfirmEmailChangeTemplate, validation.Required),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmailTemplate struct {
|
||||||
|
Body string `form:"body" json:"body"`
|
||||||
|
Subject string `form:"subject" json:"subject"`
|
||||||
|
ActionUrl string `form:"actionUrl" json:"actionUrl"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate makes EmailTemplate validatable by implementing [validation.Validatable] interface.
|
||||||
|
func (t EmailTemplate) Validate() error {
|
||||||
|
return validation.ValidateStruct(&t,
|
||||||
|
validation.Field(&t.Subject, validation.Required),
|
||||||
validation.Field(
|
validation.Field(
|
||||||
&c.UserVerificationUrl,
|
&t.Body,
|
||||||
validation.Required,
|
validation.Required,
|
||||||
validation.By(c.checkPlaceholders(EmailPlaceholderToken)),
|
validation.By(checkPlaceholderParams(EmailPlaceholderActionUrl)),
|
||||||
),
|
),
|
||||||
validation.Field(
|
validation.Field(
|
||||||
&c.UserResetPasswordUrl,
|
&t.ActionUrl,
|
||||||
validation.Required,
|
validation.Required,
|
||||||
validation.By(c.checkPlaceholders(EmailPlaceholderToken)),
|
validation.By(checkPlaceholderParams(EmailPlaceholderToken)),
|
||||||
),
|
|
||||||
validation.Field(
|
|
||||||
&c.UserConfirmEmailChangeUrl,
|
|
||||||
validation.Required,
|
|
||||||
validation.By(c.checkPlaceholders(EmailPlaceholderToken)),
|
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MetaConfig) checkPlaceholders(params ...string) validation.RuleFunc {
|
func checkPlaceholderParams(params ...string) validation.RuleFunc {
|
||||||
return func(value any) error {
|
return func(value any) error {
|
||||||
v, _ := value.(string)
|
v, _ := value.(string)
|
||||||
if v == "" {
|
|
||||||
return nil // nothing to check
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, param := range params {
|
for _, param := range params {
|
||||||
if !strings.Contains(v, param) {
|
if !strings.Contains(v, param) {
|
||||||
return validation.NewError("validation_missing_required_param", fmt.Sprintf("Missing required parameter %q", param))
|
return validation.NewError(
|
||||||
|
"validation_missing_required_param",
|
||||||
|
fmt.Sprintf("Missing required parameter %q", param),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -318,6 +330,50 @@ func (c *MetaConfig) checkPlaceholders(params ...string) validation.RuleFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resolve replaces the placeholder parameters in the current email
|
||||||
|
// template and returns its components as ready-to-use strings.
|
||||||
|
func (t EmailTemplate) Resolve(
|
||||||
|
appName string,
|
||||||
|
appUrl,
|
||||||
|
token string,
|
||||||
|
) (subject, body, actionUrl string) {
|
||||||
|
// replace action url placeholder params (if any)
|
||||||
|
actionUrlParams := map[string]string{
|
||||||
|
EmailPlaceholderAppName: appName,
|
||||||
|
EmailPlaceholderAppUrl: appUrl,
|
||||||
|
EmailPlaceholderToken: token,
|
||||||
|
}
|
||||||
|
actionUrl = t.ActionUrl
|
||||||
|
for k, v := range actionUrlParams {
|
||||||
|
actionUrl = strings.ReplaceAll(actionUrl, k, v)
|
||||||
|
}
|
||||||
|
actionUrl, _ = rest.NormalizeUrl(actionUrl)
|
||||||
|
|
||||||
|
// replace body placeholder params (if any)
|
||||||
|
bodyParams := map[string]string{
|
||||||
|
EmailPlaceholderAppName: appName,
|
||||||
|
EmailPlaceholderAppUrl: appUrl,
|
||||||
|
EmailPlaceholderToken: token,
|
||||||
|
EmailPlaceholderActionUrl: actionUrl,
|
||||||
|
}
|
||||||
|
body = t.Body
|
||||||
|
for k, v := range bodyParams {
|
||||||
|
body = strings.ReplaceAll(body, k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace subject placeholder params (if any)
|
||||||
|
subjectParams := map[string]string{
|
||||||
|
EmailPlaceholderAppName: appName,
|
||||||
|
EmailPlaceholderAppUrl: appUrl,
|
||||||
|
}
|
||||||
|
subject = t.Subject
|
||||||
|
for k, v := range subjectParams {
|
||||||
|
subject = strings.ReplaceAll(subject, k, v)
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject, body, actionUrl
|
||||||
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
type LogsConfig struct {
|
type LogsConfig struct {
|
||||||
|
@ -333,6 +389,35 @@ func (c LogsConfig) Validate() error {
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
|
type EmailAuthConfig struct {
|
||||||
|
Enabled bool `form:"enabled" json:"enabled"`
|
||||||
|
ExceptDomains []string `form:"exceptDomains" json:"exceptDomains"`
|
||||||
|
OnlyDomains []string `form:"onlyDomains" json:"onlyDomains"`
|
||||||
|
MinPasswordLength int `form:"minPasswordLength" json:"minPasswordLength"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate makes `EmailAuthConfig` validatable by implementing [validation.Validatable] interface.
|
||||||
|
func (c EmailAuthConfig) Validate() error {
|
||||||
|
return validation.ValidateStruct(&c,
|
||||||
|
validation.Field(
|
||||||
|
&c.ExceptDomains,
|
||||||
|
validation.When(len(c.OnlyDomains) > 0, validation.Empty).Else(validation.Each(is.Domain)),
|
||||||
|
),
|
||||||
|
validation.Field(
|
||||||
|
&c.OnlyDomains,
|
||||||
|
validation.When(len(c.ExceptDomains) > 0, validation.Empty).Else(validation.Each(is.Domain)),
|
||||||
|
),
|
||||||
|
validation.Field(
|
||||||
|
&c.MinPasswordLength,
|
||||||
|
validation.When(c.Enabled, validation.Required),
|
||||||
|
validation.Min(5),
|
||||||
|
validation.Max(100),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// -------------------------------------------------------------------
|
||||||
|
|
||||||
type AuthProviderConfig struct {
|
type AuthProviderConfig struct {
|
||||||
Enabled bool `form:"enabled" json:"enabled"`
|
Enabled bool `form:"enabled" json:"enabled"`
|
||||||
AllowRegistrations bool `form:"allowRegistrations" json:"allowRegistrations"`
|
AllowRegistrations bool `form:"allowRegistrations" json:"allowRegistrations"`
|
||||||
|
@ -382,32 +467,3 @@ func (c AuthProviderConfig) SetupProvider(provider auth.Provider) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------------------------------------------------------
|
|
||||||
|
|
||||||
type EmailAuthConfig struct {
|
|
||||||
Enabled bool `form:"enabled" json:"enabled"`
|
|
||||||
ExceptDomains []string `form:"exceptDomains" json:"exceptDomains"`
|
|
||||||
OnlyDomains []string `form:"onlyDomains" json:"onlyDomains"`
|
|
||||||
MinPasswordLength int `form:"minPasswordLength" json:"minPasswordLength"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate makes `EmailAuthConfig` validatable by implementing [validation.Validatable] interface.
|
|
||||||
func (c EmailAuthConfig) Validate() error {
|
|
||||||
return validation.ValidateStruct(&c,
|
|
||||||
validation.Field(
|
|
||||||
&c.ExceptDomains,
|
|
||||||
validation.When(len(c.OnlyDomains) > 0, validation.Empty).Else(validation.Each(is.Domain)),
|
|
||||||
),
|
|
||||||
validation.Field(
|
|
||||||
&c.OnlyDomains,
|
|
||||||
validation.When(len(c.ExceptDomains) > 0, validation.Empty).Else(validation.Each(is.Domain)),
|
|
||||||
),
|
|
||||||
validation.Field(
|
|
||||||
&c.MinPasswordLength,
|
|
||||||
validation.When(c.Enabled, validation.Required),
|
|
||||||
validation.Min(5),
|
|
||||||
validation.Max(100),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
package core
|
||||||
|
|
||||||
|
// Common settings placeholder tokens
|
||||||
|
const (
|
||||||
|
EmailPlaceholderAppName string = "{APP_NAME}"
|
||||||
|
EmailPlaceholderAppUrl string = "{APP_URL}"
|
||||||
|
EmailPlaceholderToken string = "{TOKEN}"
|
||||||
|
EmailPlaceholderActionUrl string = "{ACTION_URL}"
|
||||||
|
)
|
||||||
|
|
||||||
|
var defaultVerificationTemplate = EmailTemplate{
|
||||||
|
Subject: "Verify your " + EmailPlaceholderAppName + " email",
|
||||||
|
Body: `<p>Hello,</p>
|
||||||
|
<p>Thank you for joining us at ` + EmailPlaceholderAppName + `.</p>
|
||||||
|
<p>Click on the button below to verify your email address.</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn" href="` + EmailPlaceholderActionUrl + `" target="_blank" rel="noopener">Verify</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Thanks,<br/>
|
||||||
|
` + EmailPlaceholderAppName + ` team
|
||||||
|
</p>`,
|
||||||
|
ActionUrl: EmailPlaceholderAppUrl + "/_/#/users/confirm-verification/" + EmailPlaceholderToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultResetPasswordTemplate = EmailTemplate{
|
||||||
|
Subject: "Reset your " + EmailPlaceholderAppName + " password",
|
||||||
|
Body: `<p>Hello,</p>
|
||||||
|
<p>Click on the button below to reset your password.</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn" href="` + EmailPlaceholderActionUrl + `" target="_blank" rel="noopener">Reset password</a>
|
||||||
|
</p>
|
||||||
|
<p><i>If you didn't ask to reset your password, you can ignore this email.</i></p>
|
||||||
|
<p>
|
||||||
|
Thanks,<br/>
|
||||||
|
` + EmailPlaceholderAppName + ` team
|
||||||
|
</p>`,
|
||||||
|
ActionUrl: EmailPlaceholderAppUrl + "/_/#/users/confirm-password-reset/" + EmailPlaceholderToken,
|
||||||
|
}
|
||||||
|
|
||||||
|
var defaultConfirmEmailChangeTemplate = EmailTemplate{
|
||||||
|
Subject: "Confirm your " + EmailPlaceholderAppName + " new email address",
|
||||||
|
Body: `<p>Hello,</p>
|
||||||
|
<p>Click on the button below to confirm your new email address.</p>
|
||||||
|
<p>
|
||||||
|
<a class="btn" href="` + EmailPlaceholderActionUrl + `" target="_blank" rel="noopener">Confirm new email</a>
|
||||||
|
</p>
|
||||||
|
<p><i>If you didn't ask to change your email address, you can ignore this email.</i></p>
|
||||||
|
<p>
|
||||||
|
Thanks,<br/>
|
||||||
|
` + EmailPlaceholderAppName + ` team
|
||||||
|
</p>`,
|
||||||
|
ActionUrl: EmailPlaceholderAppUrl + "/_/#/users/confirm-email-change/" + EmailPlaceholderToken,
|
||||||
|
}
|
|
@ -2,9 +2,11 @@ package core_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
validation "github.com/go-ozzo/ozzo-validation/v4"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/tools/auth"
|
"github.com/pocketbase/pocketbase/tools/auth"
|
||||||
)
|
)
|
||||||
|
@ -172,7 +174,7 @@ func TestSettingsRedactClone(t *testing.T) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := `{"meta":{"appName":"test123","appUrl":"http://localhost:8090","senderName":"Support","senderAddress":"support@example.com","userVerificationUrl":"%APP_URL%/_/#/users/confirm-verification/%TOKEN%","userResetPasswordUrl":"%APP_URL%/_/#/users/confirm-password-reset/%TOKEN%","userConfirmEmailChangeUrl":"%APP_URL%/_/#/users/confirm-email-change/%TOKEN%"},"logs":{"maxDays":7},"smtp":{"enabled":false,"host":"smtp.example.com","port":587,"username":"","password":"******","tls":true},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","secret":"******","forcePathStyle":false},"adminAuthToken":{"secret":"******","duration":1209600},"adminPasswordResetToken":{"secret":"******","duration":1800},"userAuthToken":{"secret":"******","duration":1209600},"userPasswordResetToken":{"secret":"******","duration":1800},"userEmailChangeToken":{"secret":"******","duration":1800},"userVerificationToken":{"secret":"******","duration":604800},"emailAuth":{"enabled":true,"exceptDomains":null,"onlyDomains":null,"minPasswordLength":8},"googleAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"},"facebookAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"},"githubAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"},"gitlabAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"}}`
|
expected := `{"meta":{"appName":"test123","appUrl":"http://localhost:8090","senderName":"Support","senderAddress":"support@example.com","verificationTemplate":{"body":"\u003cp\u003eHello,\u003c/p\u003e\n\u003cp\u003eThank you for joining us at {APP_NAME}.\u003c/p\u003e\n\u003cp\u003eClick on the button below to verify your email address.\u003c/p\u003e\n\u003cp\u003e\n \u003ca class=\"btn\" href=\"{ACTION_URL}\" target=\"_blank\" rel=\"noopener\"\u003eVerify\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp\u003e\n Thanks,\u003cbr/\u003e\n {APP_NAME} team\n\u003c/p\u003e","subject":"Verify your {APP_NAME} email","actionUrl":"{APP_URL}/_/#/users/confirm-verification/{TOKEN}"},"resetPasswordTemplate":{"body":"\u003cp\u003eHello,\u003c/p\u003e\n\u003cp\u003eClick on the button below to reset your password.\u003c/p\u003e\n\u003cp\u003e\n \u003ca class=\"btn\" href=\"{ACTION_URL}\" target=\"_blank\" rel=\"noopener\"\u003eReset password\u003c/a\u003e\n\u003c/p\u003e\n\u003cp\u003e\u003ci\u003eIf you didn't ask to reset your password, you can ignore this email.\u003c/i\u003e\u003c/p\u003e\n\u003cp\u003e\n Thanks,\u003cbr/\u003e\n {APP_NAME} team\n\u003c/p\u003e","subject":"Reset your {APP_NAME} password","actionUrl":"{APP_URL}/_/#/users/confirm-password-reset/{TOKEN}"},"confirmEmailChangeTemplate":{"body":"\u003cp\u003eHello,\u003c/p\u003e\n\u003cp\u003eClick on the button below to confirm your new email address.\u003c/p\u003e\n\u003cp\u003e\n \u003ca class=\"btn\" href=\"{ACTION_URL}\" target=\"_blank\" rel=\"noopener\"\u003eConfirm new email\u003c/a\u003e\n\u003c/p\u003e\n\u003cp\u003e\u003ci\u003eIf you didn't ask to change your email address, you can ignore this email.\u003c/i\u003e\u003c/p\u003e\n\u003cp\u003e\n Thanks,\u003cbr/\u003e\n {APP_NAME} team\n\u003c/p\u003e","subject":"Confirm your {APP_NAME} new email address","actionUrl":"{APP_URL}/_/#/users/confirm-email-change/{TOKEN}"}},"logs":{"maxDays":7},"smtp":{"enabled":false,"host":"smtp.example.com","port":587,"username":"","password":"******","tls":true},"s3":{"enabled":false,"bucket":"","region":"","endpoint":"","accessKey":"","secret":"******","forcePathStyle":false},"adminAuthToken":{"secret":"******","duration":1209600},"adminPasswordResetToken":{"secret":"******","duration":1800},"userAuthToken":{"secret":"******","duration":1209600},"userPasswordResetToken":{"secret":"******","duration":1800},"userEmailChangeToken":{"secret":"******","duration":1800},"userVerificationToken":{"secret":"******","duration":604800},"emailAuth":{"enabled":true,"exceptDomains":null,"onlyDomains":null,"minPasswordLength":8},"googleAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"},"facebookAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"},"githubAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"},"gitlabAuth":{"enabled":false,"allowRegistrations":true,"clientSecret":"******"}}`
|
||||||
|
|
||||||
if encodedStr := string(encoded); encodedStr != expected {
|
if encodedStr := string(encoded); encodedStr != expected {
|
||||||
t.Fatalf("Expected %v, got \n%v", expected, encodedStr)
|
t.Fatalf("Expected %v, got \n%v", expected, encodedStr)
|
||||||
|
@ -355,6 +357,24 @@ func TestS3ConfigValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMetaConfigValidate(t *testing.T) {
|
func TestMetaConfigValidate(t *testing.T) {
|
||||||
|
invalidTemplate := core.EmailTemplate{
|
||||||
|
Subject: "test",
|
||||||
|
ActionUrl: "test",
|
||||||
|
Body: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
noPlaceholdersTemplate := core.EmailTemplate{
|
||||||
|
Subject: "test",
|
||||||
|
ActionUrl: "http://example.com",
|
||||||
|
Body: "test",
|
||||||
|
}
|
||||||
|
|
||||||
|
withPlaceholdersTemplate := core.EmailTemplate{
|
||||||
|
Subject: "test",
|
||||||
|
ActionUrl: "http://example.com" + core.EmailPlaceholderToken,
|
||||||
|
Body: "test" + core.EmailPlaceholderActionUrl,
|
||||||
|
}
|
||||||
|
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.MetaConfig
|
config core.MetaConfig
|
||||||
expectError bool
|
expectError bool
|
||||||
|
@ -367,39 +387,39 @@ func TestMetaConfigValidate(t *testing.T) {
|
||||||
// invalid data
|
// invalid data
|
||||||
{
|
{
|
||||||
core.MetaConfig{
|
core.MetaConfig{
|
||||||
AppName: strings.Repeat("a", 300),
|
AppName: strings.Repeat("a", 300),
|
||||||
AppUrl: "test",
|
AppUrl: "test",
|
||||||
SenderName: strings.Repeat("a", 300),
|
SenderName: strings.Repeat("a", 300),
|
||||||
SenderAddress: "invalid_email",
|
SenderAddress: "invalid_email",
|
||||||
UserVerificationUrl: "test",
|
VerificationTemplate: invalidTemplate,
|
||||||
UserResetPasswordUrl: "test",
|
ResetPasswordTemplate: invalidTemplate,
|
||||||
UserConfirmEmailChangeUrl: "test",
|
ConfirmEmailChangeTemplate: invalidTemplate,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// invalid data (missing required placeholders)
|
// invalid data (missing required placeholders)
|
||||||
{
|
{
|
||||||
core.MetaConfig{
|
core.MetaConfig{
|
||||||
AppName: "test",
|
AppName: "test",
|
||||||
AppUrl: "https://example.com",
|
AppUrl: "https://example.com",
|
||||||
SenderName: "test",
|
SenderName: "test",
|
||||||
SenderAddress: "test@example.com",
|
SenderAddress: "test@example.com",
|
||||||
UserVerificationUrl: "https://example.com",
|
VerificationTemplate: noPlaceholdersTemplate,
|
||||||
UserResetPasswordUrl: "https://example.com",
|
ResetPasswordTemplate: noPlaceholdersTemplate,
|
||||||
UserConfirmEmailChangeUrl: "https://example.com",
|
ConfirmEmailChangeTemplate: noPlaceholdersTemplate,
|
||||||
},
|
},
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
// valid data
|
// valid data
|
||||||
{
|
{
|
||||||
core.MetaConfig{
|
core.MetaConfig{
|
||||||
AppName: "test",
|
AppName: "test",
|
||||||
AppUrl: "https://example.com",
|
AppUrl: "https://example.com",
|
||||||
SenderName: "test",
|
SenderName: "test",
|
||||||
SenderAddress: "test@example.com",
|
SenderAddress: "test@example.com",
|
||||||
UserVerificationUrl: "https://example.com/" + core.EmailPlaceholderToken,
|
VerificationTemplate: withPlaceholdersTemplate,
|
||||||
UserResetPasswordUrl: "https://example.com/" + core.EmailPlaceholderToken,
|
ResetPasswordTemplate: withPlaceholdersTemplate,
|
||||||
UserConfirmEmailChangeUrl: "https://example.com/" + core.EmailPlaceholderToken,
|
ConfirmEmailChangeTemplate: withPlaceholdersTemplate,
|
||||||
},
|
},
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
@ -418,6 +438,130 @@ func TestMetaConfigValidate(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEmailTemplateValidate(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
emailTemplate core.EmailTemplate
|
||||||
|
expectedErrors []string
|
||||||
|
}{
|
||||||
|
// require values
|
||||||
|
{
|
||||||
|
core.EmailTemplate{},
|
||||||
|
[]string{"subject", "actionUrl", "body"},
|
||||||
|
},
|
||||||
|
// missing placeholders
|
||||||
|
{
|
||||||
|
core.EmailTemplate{
|
||||||
|
Subject: "test",
|
||||||
|
ActionUrl: "test",
|
||||||
|
Body: "test",
|
||||||
|
},
|
||||||
|
[]string{"actionUrl", "body"},
|
||||||
|
},
|
||||||
|
// valid data
|
||||||
|
{
|
||||||
|
core.EmailTemplate{
|
||||||
|
Subject: "test",
|
||||||
|
ActionUrl: "test" + core.EmailPlaceholderToken,
|
||||||
|
Body: "test" + core.EmailPlaceholderActionUrl,
|
||||||
|
},
|
||||||
|
[]string{},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
result := s.emailTemplate.Validate()
|
||||||
|
|
||||||
|
// parse errors
|
||||||
|
errs, ok := result.(validation.Errors)
|
||||||
|
if !ok && result != nil {
|
||||||
|
t.Errorf("(%d) Failed to parse errors %v", i, result)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// check errors
|
||||||
|
if len(errs) > len(s.expectedErrors) {
|
||||||
|
t.Errorf("(%d) Expected error keys %v, got %v", i, s.expectedErrors, errs)
|
||||||
|
}
|
||||||
|
for _, k := range s.expectedErrors {
|
||||||
|
if _, ok := errs[k]; !ok {
|
||||||
|
t.Errorf("(%d) Missing expected error key %q in %v", i, k, errs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEmailTemplateResolve(t *testing.T) {
|
||||||
|
allPlaceholders := core.EmailPlaceholderActionUrl + core.EmailPlaceholderToken + core.EmailPlaceholderAppName + core.EmailPlaceholderAppUrl
|
||||||
|
|
||||||
|
scenarios := []struct {
|
||||||
|
emailTemplate core.EmailTemplate
|
||||||
|
expectedSubject string
|
||||||
|
expectedBody string
|
||||||
|
expectedActionUrl string
|
||||||
|
}{
|
||||||
|
// no placeholders
|
||||||
|
{
|
||||||
|
emailTemplate: core.EmailTemplate{
|
||||||
|
Subject: "subject:",
|
||||||
|
Body: "body:",
|
||||||
|
ActionUrl: "/actionUrl////",
|
||||||
|
},
|
||||||
|
expectedSubject: "subject:",
|
||||||
|
expectedActionUrl: "/actionUrl/",
|
||||||
|
expectedBody: "body:",
|
||||||
|
},
|
||||||
|
// with placeholders
|
||||||
|
{
|
||||||
|
emailTemplate: core.EmailTemplate{
|
||||||
|
ActionUrl: "/actionUrl////" + allPlaceholders,
|
||||||
|
Subject: "subject:" + allPlaceholders,
|
||||||
|
Body: "body:" + allPlaceholders,
|
||||||
|
},
|
||||||
|
expectedActionUrl: fmt.Sprintf(
|
||||||
|
"/actionUrl/%%7BACTION_URL%%7D%s%s%s",
|
||||||
|
"token_test",
|
||||||
|
"name_test",
|
||||||
|
"url_test",
|
||||||
|
),
|
||||||
|
expectedSubject: fmt.Sprintf(
|
||||||
|
"subject:%s%s%s%s",
|
||||||
|
core.EmailPlaceholderActionUrl,
|
||||||
|
core.EmailPlaceholderToken,
|
||||||
|
"name_test",
|
||||||
|
"url_test",
|
||||||
|
),
|
||||||
|
expectedBody: fmt.Sprintf(
|
||||||
|
"body:%s%s%s%s",
|
||||||
|
fmt.Sprintf(
|
||||||
|
"/actionUrl/%%7BACTION_URL%%7D%s%s%s",
|
||||||
|
"token_test",
|
||||||
|
"name_test",
|
||||||
|
"url_test",
|
||||||
|
),
|
||||||
|
"token_test",
|
||||||
|
"name_test",
|
||||||
|
"url_test",
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
subject, body, actionUrl := s.emailTemplate.Resolve("name_test", "url_test", "token_test")
|
||||||
|
|
||||||
|
if s.expectedSubject != subject {
|
||||||
|
t.Errorf("(%d) Expected subject %q got %q", i, s.expectedSubject, subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.expectedBody != body {
|
||||||
|
t.Errorf("(%d) Expected body \n%v got \n%v", i, s.expectedBody, body)
|
||||||
|
}
|
||||||
|
|
||||||
|
if s.expectedActionUrl != actionUrl {
|
||||||
|
t.Errorf("(%d) Expected actionUrl \n%v got \n%v", i, s.expectedActionUrl, actionUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestLogsConfigValidate(t *testing.T) {
|
func TestLogsConfigValidate(t *testing.T) {
|
||||||
scenarios := []struct {
|
scenarios := []struct {
|
||||||
config core.LogsConfig
|
config core.LogsConfig
|
||||||
|
|
79
go.mod
79
go.mod
|
@ -4,7 +4,7 @@ go 1.18
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/AlecAivazis/survey/v2 v2.3.5
|
github.com/AlecAivazis/survey/v2 v2.3.5
|
||||||
github.com/aws/aws-sdk-go v1.44.48
|
github.com/aws/aws-sdk-go v1.44.76
|
||||||
github.com/disintegration/imaging v1.6.2
|
github.com/disintegration/imaging v1.6.2
|
||||||
github.com/domodwyer/mailyak/v3 v3.3.3
|
github.com/domodwyer/mailyak/v3 v3.3.3
|
||||||
github.com/fatih/color v1.13.0
|
github.com/fatih/color v1.13.0
|
||||||
|
@ -13,44 +13,41 @@ require (
|
||||||
github.com/golang-jwt/jwt/v4 v4.4.2
|
github.com/golang-jwt/jwt/v4 v4.4.2
|
||||||
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
|
github.com/labstack/echo/v5 v5.0.0-20220201181537-ed2888cfa198
|
||||||
github.com/mattn/go-sqlite3 v1.14.14
|
github.com/mattn/go-sqlite3 v1.14.14
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19
|
|
||||||
github.com/pocketbase/dbx v1.6.0
|
github.com/pocketbase/dbx v1.6.0
|
||||||
github.com/spf13/cast v1.5.0
|
github.com/spf13/cast v1.5.0
|
||||||
github.com/spf13/cobra v1.5.0
|
github.com/spf13/cobra v1.5.0
|
||||||
gocloud.dev v0.25.0
|
gocloud.dev v0.26.0
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa
|
||||||
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0
|
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7
|
||||||
modernc.org/sqlite v1.17.3
|
modernc.org/sqlite v1.18.1
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.7 // indirect
|
github.com/aws/aws-sdk-go-v2 v1.16.11 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 // indirect
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.13 // indirect
|
github.com/aws/aws-sdk-go-v2/config v1.16.1 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.8 // indirect
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.13 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.19 // indirect
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.25 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 // indirect
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.9 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.13 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8 // indirect
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1 // indirect
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.11 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.16 // indirect
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 // indirect
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 // indirect
|
||||||
github.com/aws/smithy-go v1.12.0 // indirect
|
github.com/aws/smithy-go v1.12.1 // indirect
|
||||||
github.com/aymerick/douceur v0.2.0 // indirect
|
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/google/uuid v1.3.0 // indirect
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/google/wire v0.5.0 // indirect
|
github.com/google/wire v0.5.0 // indirect
|
||||||
github.com/googleapis/gax-go/v2 v2.4.0 // indirect
|
github.com/googleapis/gax-go/v2 v2.5.1 // indirect
|
||||||
github.com/gorilla/css v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.1 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
|
||||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||||
|
@ -61,24 +58,24 @@ require (
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasttemplate v1.2.1 // indirect
|
github.com/valyala/fasttemplate v1.2.1 // indirect
|
||||||
go.opencensus.io v0.23.0 // indirect
|
go.opencensus.io v0.23.0 // indirect
|
||||||
golang.org/x/image v0.0.0-20220617043117-41969df76e82 // indirect
|
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 // indirect
|
||||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 // indirect
|
||||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 // indirect
|
golang.org/x/net v0.0.0-20220812174116-3211cb980234 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e // indirect
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
|
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 // indirect
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
|
||||||
golang.org/x/tools v0.1.11 // indirect
|
golang.org/x/tools v0.1.12 // indirect
|
||||||
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
golang.org/x/xerrors v0.0.0-20220609144429-65e65417b02f // indirect
|
||||||
google.golang.org/api v0.86.0 // indirect
|
google.golang.org/api v0.92.0 // indirect
|
||||||
google.golang.org/appengine v1.6.7 // indirect
|
google.golang.org/appengine v1.6.7 // indirect
|
||||||
google.golang.org/genproto v0.0.0-20220706132729-d86698d07c53 // indirect
|
google.golang.org/genproto v0.0.0-20220812140447-cec7f5303424 // indirect
|
||||||
google.golang.org/grpc v1.47.0 // indirect
|
google.golang.org/grpc v1.48.0 // indirect
|
||||||
google.golang.org/protobuf v1.28.0 // indirect
|
google.golang.org/protobuf v1.28.1 // indirect
|
||||||
lukechampine.com/uint128 v1.2.0 // indirect
|
lukechampine.com/uint128 v1.2.0 // indirect
|
||||||
modernc.org/cc/v3 v3.36.0 // indirect
|
modernc.org/cc/v3 v3.36.1 // indirect
|
||||||
modernc.org/ccgo/v3 v3.16.6 // indirect
|
modernc.org/ccgo/v3 v3.16.8 // indirect
|
||||||
modernc.org/libc v1.16.14 // indirect
|
modernc.org/libc v1.16.19 // indirect
|
||||||
modernc.org/mathutil v1.4.1 // indirect
|
modernc.org/mathutil v1.4.1 // indirect
|
||||||
modernc.org/memory v1.1.1 // indirect
|
modernc.org/memory v1.1.1 // indirect
|
||||||
modernc.org/opt v0.1.3 // indirect
|
modernc.org/opt v0.1.3 // indirect
|
||||||
|
|
163
go.sum
163
go.sum
|
@ -122,68 +122,66 @@ github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d/go.mod h1:W
|
||||||
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
|
||||||
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
github.com/aws/aws-sdk-go v1.37.0/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
|
||||||
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
github.com/aws/aws-sdk-go v1.43.31/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
github.com/aws/aws-sdk-go v1.44.48 h1:jLDC9RsNoYMLFlKpB8LdqUnoDdC2yvkS4QbuyPQJ8+M=
|
github.com/aws/aws-sdk-go v1.44.76 h1:5e8yGO/XeNYKckOjpBKUd5wStf0So3CrQIiOMCVLpOI=
|
||||||
github.com/aws/aws-sdk-go v1.44.48/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
github.com/aws/aws-sdk-go v1.44.76/go.mod h1:y4AeaBuwd2Lk+GepC1E9v0qOiTws0MIWAX4oIKwKHZo=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
github.com/aws/aws-sdk-go-v2 v1.16.2/go.mod h1:ytwTPBG6fXTZLxxeeCCWj2/EMYp/xDUgX+OET6TLNNU=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.7 h1:zfBwXus3u14OszRxGcqCDS4MfMCv10e8SMJ2r8Xm0Ns=
|
github.com/aws/aws-sdk-go-v2 v1.16.11 h1:xM1ZPSvty3xVmdxiGr7ay/wlqv+MWhH0rMlyLdbC0YQ=
|
||||||
github.com/aws/aws-sdk-go-v2 v1.16.7/go.mod h1:6CpKuLXg2w7If3ABZCl/qZ6rEgwtjZTn4eAf4RcEyuw=
|
github.com/aws/aws-sdk-go-v2 v1.16.11/go.mod h1:WTACcleLz6VZTp7fak4EO5b9Q4foxbn+8PIz3PmyKlo=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.1/go.mod h1:n8Bs1ElDD2wJ9kCRTczA83gYbBmjSwZp3umc6zF4EeM=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3 h1:S/ZBwevQkr7gv5YxONYpGQxlMFFYSRfz3RMcjsC9Qhk=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4 h1:zfT11pa7ifu/VlLDpmc5OY2W4nYmnKkFDGeMVnmqAI0=
|
||||||
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.3/go.mod h1:gNsR5CaXKmQSSzrmGxmwmct/r+ZBfbxorAuXYsj/M5Y=
|
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.4.4/go.mod h1:ES0I1GBs+YYgcDS1ek47Erbn4TOL811JKqBXtgzqyZ8=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
|
github.com/aws/aws-sdk-go-v2/config v1.15.3/go.mod h1:9YL3v07Xc/ohTsxFXzan9ZpFpdTOFl4X65BAKYaz8jg=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.13 h1:CJH9zn/Enst7lDiGpoguVt0lZr5HcpNVlRJWbJ6qreo=
|
github.com/aws/aws-sdk-go-v2/config v1.16.1 h1:jasqFPOoNPXHOYGEEuvyT87ACiXhD3OkQckIm5uqi5I=
|
||||||
github.com/aws/aws-sdk-go-v2/config v1.15.13/go.mod h1:AcMu50uhV6wMBUlURnEXhr9b3fX6FLSTlEV89krTEGk=
|
github.com/aws/aws-sdk-go-v2/config v1.16.1/go.mod h1:4SKzBMiB8lV0fw2w7eDBo/LjQyHFITN4vUUuqpurFmI=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
|
github.com/aws/aws-sdk-go-v2/credentials v1.11.2/go.mod h1:j8YsY9TXTm31k4eFhspiQicfXPLZ0gYXA50i4gxPE8g=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.8 h1:niTa7zc7uyOP2ufri0jPESBt1h9yP3Zc0q+xzih3h8o=
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.13 h1:cuPzIsjKAWBUAAk8ZUR2l02Sxafl9hiaMsc7tlnjwAY=
|
||||||
github.com/aws/aws-sdk-go-v2/credentials v1.12.8/go.mod h1:P2Hd4Sy7mXRxPNcQMPBmqszSJoDXexX8XEDaT6lucO0=
|
github.com/aws/aws-sdk-go-v2/credentials v1.12.13/go.mod h1:9fDEemXizwXrxPU1MTzv69LP/9D8HVl5qHAQO9A9ikY=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.3/go.mod h1:uk1vhHHERfSVCUnqSqz8O48LBYDSC+k6brng09jcMOk=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8 h1:VfBdn2AxwMbFyJN/lF/xuT3SakomJ86PZu3rCxb5K0s=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12 h1:wgJBHO58Pc1V1QAnzdVM3JK3WbE/6eUF0JxCZ+/izz0=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.8/go.mod h1:oL1Q3KuCq1D4NykQnIvtRiBGLUXhcpY5pl6QZB2XEPU=
|
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.12.12/go.mod h1:aZ4vZnyUuxedC7eD4JyEHpGnCz+O2sHQEx3VvAwklSE=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.3/go.mod h1:0dHuD2HZZSiwfJSy1FO5bX1hQ1TxVV1QXXjpn3XUE44=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.19 h1:WfCYqsAADDRNCQQ5LGcrlqbR7SK3PYrP/UCh7qNGBQM=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.25 h1:ShUxLkMxarXylGxfYwg8p+xEKY+C1y54oUU3wFsUMFo=
|
||||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.19/go.mod h1:koLPv2oF6ksE3zBKLDP0GFmKfaCmYwVHqGIbaPrHIRg=
|
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.11.25/go.mod h1:cam5wV1ebd3ZVuh2r2CA8FtSAA/eUMtRH4owk0ygfFs=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.9/go.mod h1:AnVH5pvai0pAF4lXRq0bmhbes1u9R8wTE+g+183bZNM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14 h1:2C0pYHcUBmdzPj+EKNC4qj97oK6yjrUhc1KoSodglvk=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18 h1:OmiwoVyLKEqqD5GvB683dbSqxiOfvx4U2lDZhG2Esc4=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.14/go.mod h1:kdjrMwHwrC3+FsKhNcCMJ7tUVj/8uSD5CZXeQ4wV6fM=
|
github.com/aws/aws-sdk-go-v2/internal/configsources v1.1.18/go.mod h1:348MLhzV1GSlZSMusdwQpXKbhD7X2gbI/TxwAPKkYZQ=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.3/go.mod h1:ssOhaLpRlh88H3UmEcsBoVKq309quMvm3Ds8e9d4eJM=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8 h1:2J+jdlBJWEmTyAwC82Ym68xCykIvnSnIN18b8xHGlcc=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12 h1:5mvQDtNWtI6H56+E4LUnLWEmATMB7oEh+Z9RurtIuC0=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.8/go.mod h1:ZIV8GYoC6WLBW5KGs+o4rsc65/ozd+eQ0L31XF5VDwk=
|
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.4.12/go.mod h1:ckaCVTEdGAxO6KwTGzgskxR1xM+iJW4lxMyDFVda2Fc=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.10/go.mod h1:8DcYQcz0+ZJaSxANlHIsbbi6S+zMwjwdDqwW3r9AzaE=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15 h1:QquxR7NH3ULBsKC+NoTpilzbKKS+5AELfNREInbhvas=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19 h1:g5qq9sgtEzt2szMaDqQO6fqKe026T6dHTFJp5NsPzkQ=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.15/go.mod h1:Tkrthp/0sNBShQQsamR7j/zY4p19tVTAs+nnqhH6R3c=
|
github.com/aws/aws-sdk-go-v2/internal/ini v1.3.19/go.mod h1:cVHo8KTuHjShb9V8/VjH3S/8+xPu16qx8fdGwmotJhE=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5 h1:tEEHn+PGAxRVqMPEhtU8oCSW/1Ge3zP5nUgPrGQNUPs=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.9 h1:agLpf3vtYX1rtKTrOGpevdP3iC2W0hKDmzmhhxJzL+A=
|
||||||
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.5/go.mod h1:aIwFF3dUk95ocCcA3zfk3nhz0oLkpzHFWuMp8l/4nNs=
|
github.com/aws/aws-sdk-go-v2/internal/v4a v1.0.9/go.mod h1:cv+n1mdyh+0B8tAtlEBzTYFA2Uv15SISEn6kabYhIgE=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.1/go.mod h1:GeUru+8VzrTXV/83XyMJ80KpH8xO89VPoUileyNQ+tc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3 h1:4n4KCtv5SUoT5Er5XV41huuzrCqepxlW3SDI9qHQebc=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.5 h1:g1ITJ9i9ixa+/WVggLNK20KyliAA8ltnuxfZEDfo2hM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.3/go.mod h1:gkb2qADY+OHaGLKNTYxMaQNacfeyQpZ4csDTQMeFmcw=
|
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.9.5/go.mod h1:oehQLbMQkppKLXvpx/1Eo0X47Fe+0971DXC9UjGnKcI=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3/go.mod h1:Seb8KNmD6kVTjwRjVEgOT5hPin6sq+v4C2ycJQDwuH8=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.3/go.mod h1:Seb8KNmD6kVTjwRjVEgOT5hPin6sq+v4C2ycJQDwuH8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9 h1:gVv2vXOMqJeR4ZHHV32K7LElIJIIzyw/RU1b0lSfWTQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.13 h1:3GamN8jcdz/a3nvL/ZVtoH/6xxeshfsiXj5O+6GW4Rg=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.9/go.mod h1:EF5RLnD9l0xvEWwMRcktIS/dI6lF8lU5eV3B13k6sWo=
|
github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.1.13/go.mod h1:89CSPn69UECDLVn0H6FwKNgbtirksl8C8i3aBeeeihw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.3/go.mod h1:wlY6SVjuwvh3TVRpTqdy4I1JpBFLX4UGeKZdWntaocw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8 h1:oKnAXxSF2FUvfgw8uzU/v9OTYorJJZ8eBmWhr9TWVVQ=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12 h1:7iPTTX4SAI2U2VOogD7/gmHlsgnYSgoNHt7MSQXtG2M=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.8/go.mod h1:rDVhIMAX9N2r8nWxDUlbubvvaFMnfsm+3jAV7q+rpM4=
|
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.9.12/go.mod h1:1TODGhheLWjpQWSuhYuAUWYTCKwEjx2iblIFKDHjeTc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.3/go.mod h1:Bm/v2IaN6rZ+Op7zX+bOUMdL4fsrYZiD0dsjLhNKwZc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8 h1:TlN1UC39A0LUNoD51ubO5h32haznA+oVe15jO9O4Lj0=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12 h1:QFjSOmHSb77qRTv7KI9UFon9X5wLWY5/M+6la3dTcZc=
|
||||||
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.8/go.mod h1:JlVwmWtT/1c5W+6oUsjXjAJ0iJZ+hlghdrDy/8JxGCU=
|
github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.13.12/go.mod h1:MADjAN0GHFDuc5lRa5Y5ki+oIO/w7X4qczHy+OUx0IA=
|
||||||
github.com/aws/aws-sdk-go-v2/service/kms v1.16.3/go.mod h1:QuiHPBqlOFCi4LqdSskYYAWpQlx3PKmohy+rE2F+o5g=
|
github.com/aws/aws-sdk-go-v2/service/kms v1.16.3/go.mod h1:QuiHPBqlOFCi4LqdSskYYAWpQlx3PKmohy+rE2F+o5g=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.26.3/go.mod h1:g1qvDuRsJY+XghsV6zg00Z4KJ7DtFFCx8fJD2a491Ak=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1 h1:OKQIQ0QhEBmGr2LfT952meIZz3ujrPYnxH+dO/5ldnI=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5 h1:h9qqTedYnA9JcWjKyLV6UYIMSdp91ExLCUbjbpDLH7A=
|
||||||
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.1/go.mod h1:NffjpNsMUFXp6Ok/PahrktAncoekWrywvmIK83Q2raE=
|
github.com/aws/aws-sdk-go-v2/service/s3 v1.27.5/go.mod h1:J8SS5Tp/zeLxaubB0xGfKnVrvssNBNLwTipreTKLhjQ=
|
||||||
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU8rrre0/4a0pn2wgwiDvOEzoOjcJUBr67o=
|
github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.15.4/go.mod h1:PJc8s+lxyU8rrre0/4a0pn2wgwiDvOEzoOjcJUBr67o=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sns v1.17.4/go.mod h1:kElt+uCcXxcqFyc+bQqZPFD9DME/eC6oHBXvFzQ9Bcw=
|
github.com/aws/aws-sdk-go-v2/service/sns v1.17.4/go.mod h1:kElt+uCcXxcqFyc+bQqZPFD9DME/eC6oHBXvFzQ9Bcw=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM=
|
github.com/aws/aws-sdk-go-v2/service/sqs v1.18.3/go.mod h1:skmQo0UPvsjsuYYSYMVmrPc1HWCbHUJyrCEp+ZaLzqM=
|
||||||
github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0=
|
github.com/aws/aws-sdk-go-v2/service/ssm v1.24.1/go.mod h1:NR/xoKjdbRJ+qx0pMR4mI+N/H1I1ynHwXnO6FowXJc0=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.3/go.mod h1:7UQ/e69kU7LDPtY40OyoHYgRmgfGM4mgsLYtcObdveU=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.11 h1:XOJWXNFXJyapJqQuCIPfftsOf0XZZioM0kK6OPRt9MY=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.16 h1:YK8L7TNlGwMWHYqLs+i6dlITpxqzq08FqQUy26nm+T8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sso v1.11.11/go.mod h1:MO4qguFjs3wPGcCSpQ7kOFTwRvb+eu+fn+1vKleGHUk=
|
github.com/aws/aws-sdk-go-v2/service/sso v1.11.16/go.mod h1:mS5xqLZc/6kc06IpXn5vRxdLaED+jEuaSRv5BxtnsiY=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.3/go.mod h1:bfBj0iVmsUyUg4weDB4NxktD9rDGeKSVWnjTnwbx9b8=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.9 h1:yOfILxyjmtr2ubRkRJldlHDFBhf5vw4CzhbwWIBmimQ=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13 h1:dl8T0PJlN92rvEGOEUiD0+YPYdPEaCZK0TqHukvSfII=
|
||||||
github.com/aws/aws-sdk-go-v2/service/sts v1.16.9/go.mod h1:O1IvkYxr+39hRf960Us6j0x1P8pDqhTX+oXM5kQNl/Y=
|
github.com/aws/aws-sdk-go-v2/service/sts v1.16.13/go.mod h1:Ru3QVMLygVs/07UQ3YDur1AQZZp2tUNje8wfloFttC0=
|
||||||
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
github.com/aws/smithy-go v1.11.2/go.mod h1:3xHYmszWVx2c0kIwQeEVf9uSm4fYZt67FBJnwub1bgM=
|
||||||
github.com/aws/smithy-go v1.12.0 h1:gXpeZel/jPoWQ7OEmLIgCUnhkFftqNfwWUwAHSlp1v0=
|
github.com/aws/smithy-go v1.12.1 h1:yQRC55aXN/y1W10HgwHle01DRuV9Dpf31iGkotjt3Ag=
|
||||||
github.com/aws/smithy-go v1.12.0/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
github.com/aws/smithy-go v1.12.1/go.mod h1:Tg+OJXh4MB2R/uN61Ko2f6hTZwB/ZYGOtib8J3gBHzA=
|
||||||
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
|
|
||||||
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
|
|
||||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
|
@ -370,12 +368,11 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf
|
||||||
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
|
||||||
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM=
|
||||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||||
github.com/googleapis/gax-go/v2 v2.4.0 h1:dS9eYAjhrE2RjmzYw2XAPvcXfmcQLtFEQWn0CR82awk=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.5.1 h1:kBRZU0PSuI7PspsSb/ChWoVResUcwNVIdpB049pKTiw=
|
||||||
|
github.com/googleapis/gax-go/v2 v2.5.1/go.mod h1:h6B0KMMFNtI2ddbGJn3T3ZbwkeT6yqEF02fYlzkUCyo=
|
||||||
github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA=
|
github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA=
|
||||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||||
github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
|
|
||||||
github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
|
|
||||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||||
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
|
github.com/hanwen/go-fuse v1.0.0/go.mod h1:unqXarDXqzAk0rt98O2tVndEPIpUgLD9+rwFisZH3Ok=
|
||||||
|
@ -386,8 +383,9 @@ github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u
|
||||||
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||||
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
|
||||||
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
|
||||||
|
@ -464,23 +462,19 @@ github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope
|
||||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||||
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
|
||||||
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
|
github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI=
|
||||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||||
github.com/mattn/go-ieproxy v0.0.3 h1:YkaHmK1CzE5C4O7A3hv3TCbfNDPSCf0RKZFX+VhBeYk=
|
|
||||||
github.com/mattn/go-ieproxy v0.0.3/go.mod h1:6ZpRmhBaYuBX1U2za+9rC9iCGLsSp2tftelZne7CPko=
|
|
||||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||||
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
|
||||||
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
github.com/mattn/go-sqlite3 v1.14.14 h1:qZgc/Rwetq+MtyE18WhzjokPD93dNqLGNT3QJuLvBGw=
|
||||||
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
github.com/mattn/go-sqlite3 v1.14.14/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
|
||||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
|
||||||
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19 h1:OI7hoF5FY4pFz2VA//RN8TfM0YJ2dJcl4P4APrCWy6c=
|
|
||||||
github.com/microcosm-cc/bluemonday v1.0.19/go.mod h1:QNzV2UbLK2/53oIIwTOyLUSABMkjZ4tqiyC1g/DyqxE=
|
|
||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.3.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
@ -565,8 +559,8 @@ go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||||
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
|
||||||
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
go.uber.org/zap v1.21.0/go.mod h1:wjWOCqI0f2ZZrJF/UufIOkiC8ii6tm1iqIsLo76RfJw=
|
||||||
gocloud.dev v0.25.0 h1:Y7vDq8xj7SyM848KXf32Krda2e6jQ4CLh/mTeCSqXtk=
|
gocloud.dev v0.26.0 h1:4rM/SVL0lLs+rhC0Gmc+gt/82DBpb7nbpIZKXXnfMXg=
|
||||||
gocloud.dev v0.25.0/go.mod h1:7HegHVCYZrMiU3IE1qtnzf/vRrDwLYnRNR3EhWX8x9Y=
|
gocloud.dev v0.26.0/go.mod h1:mkUgejbnbLotorqDyvedJO20XcZNTynmSeVSQS9btVg=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
|
@ -582,8 +576,8 @@ golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5y
|
||||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
golang.org/x/crypto v0.0.0-20211115234514-b4de73f9ece8/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||||
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c=
|
||||||
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||||
|
@ -597,8 +591,8 @@ golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMk
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||||
golang.org/x/image v0.0.0-20220617043117-41969df76e82 h1:KpZB5pUSBvrHltNEdK/tw0xlPeD13M6M6aGP32gKqiw=
|
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539 h1:/eM0PCrQI2xd471rI+snWuu251/+/jpBpZqir2mPdnU=
|
||||||
golang.org/x/image v0.0.0-20220617043117-41969df76e82/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
golang.org/x/image v0.0.0-20220722155232-062f8c9fd539/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
|
@ -665,7 +659,6 @@ golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qx
|
||||||
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20210610132358-84b48f89b13b/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||||
golang.org/x/net v0.0.0-20220107192237-5cfca573fb4d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
|
@ -674,8 +667,8 @@ golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su
|
||||||
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
|
||||||
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220607020251-c690dde0001d/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60 h1:8NSylCMxLW4JvserAndSgFL7aPli6A68yf0bYFTcWCM=
|
golang.org/x/net v0.0.0-20220812174116-3211cb980234 h1:RDqmgfe7SvlMWoqC3xwQ2blLO3fcWcxMa3eBLRdRW7E=
|
||||||
golang.org/x/net v0.0.0-20220706163947-c90051bbdb60/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
golang.org/x/net v0.0.0-20220812174116-3211cb980234/go.mod h1:YDH+HFinaLZZlnHAfSS6ZXJJ9M9t4Dl22yv3iI2vPwk=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
|
@ -699,8 +692,8 @@ golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j
|
||||||
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc=
|
||||||
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
golang.org/x/oauth2 v0.0.0-20220608161450-d0670ef3b1eb/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||||
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
golang.org/x/oauth2 v0.0.0-20220622183110-fd043fe589d2/go.mod h1:jaDAt6Dkxork7LmZnYtzbRWj0W47D86a3TGe0YHBvmE=
|
||||||
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0 h1:VnGaRqoLmqZH/3TMLJwYCEWkR4j1nuIU1U9TvbqsDUw=
|
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7 h1:dtndE8FcEta75/4kHF3AbpuWzV6f1LjnLrM4pe2SZrw=
|
||||||
golang.org/x/oauth2 v0.0.0-20220630143837-2104d58473e0/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
golang.org/x/oauth2 v0.0.0-20220808172628-8227340efae7/go.mod h1:h4gKUeWbJ4rQPri7E0u6Gs4e9Ri2zaLxzw5DI5XGrYg=
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
@ -776,7 +769,6 @@ golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220110181412-a018aaa089fe/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220204135822-1c1b9b1eba6a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
@ -791,14 +783,14 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e h1:CsOuNlbOuf0mzxJIefr6Q4uAUetRUwZE4qt7VfzP+xo=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||||
golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
|
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035 h1:Q5284mrmYTpACcm+eAKjKJH48BBwSyfJqmmGDTtT8Vc=
|
||||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
golang.org/x/term v0.0.0-20220722155259-a9ba230a4035/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
|
@ -814,8 +806,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858 h1:Dpdu/EMxGMFgq0CeYMh4fazTD2vtlZRYE7wyynxJb9U=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
|
||||||
golang.org/x/time v0.0.0-20220609170525-579cf78fd858/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
|
@ -874,8 +866,8 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/tools v0.1.11 h1:loJ25fNOEhSXfHrpoGj91eCUThwdNX6u24rO1xnNteY=
|
golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU=
|
||||||
golang.org/x/tools v0.1.11/go.mod h1:SgwaegtQh8clINPpECJMqnxLv9I09HLqnW3RMqW0CA4=
|
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
@ -932,8 +924,8 @@ google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69
|
||||||
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
google.golang.org/api v0.78.0/go.mod h1:1Sg78yoMLOhlQTeF+ARBoytAcH1NNyyl390YMy6rKmw=
|
||||||
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
google.golang.org/api v0.80.0/go.mod h1:xY3nI94gbvBrE0J6NHXhxOmW97HG7Khjkku6AFB3Hyg=
|
||||||
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
google.golang.org/api v0.84.0/go.mod h1:NTsGnUFJMYROtiquksZHBWtHfeMC7iYthki7Eq3pa8o=
|
||||||
google.golang.org/api v0.86.0 h1:ZAnyOHQFIuWso1BodVfSaRyffD74T9ERGFa3k1fNk/U=
|
google.golang.org/api v0.92.0 h1:8JHk7q/+rJla+iRsWj9FQ9/wjv2M1SKtpKSdmLhxPT0=
|
||||||
google.golang.org/api v0.86.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
google.golang.org/api v0.92.0/go.mod h1:+Sem1dnrKlrXMR/X0bPnMWyluQe4RsNoYfmNLhOIkzw=
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||||
|
@ -1036,8 +1028,8 @@ google.golang.org/genproto v0.0.0-20220523171625-347a074981d8/go.mod h1:RAyBrSAP
|
||||||
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220608133413-ed9918b62aac/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220616135557-88e70c0c3a90/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220624142145-8cd45d7dbd1f/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
||||||
google.golang.org/genproto v0.0.0-20220706132729-d86698d07c53 h1:liFd7OL799HvMNYG5xozhUoWDj944y+zXPDOhu4PyaM=
|
google.golang.org/genproto v0.0.0-20220812140447-cec7f5303424 h1:zZnTt15U44/Txe/9cN/tVbteBkPMiyXK48hPsKRmqj4=
|
||||||
google.golang.org/genproto v0.0.0-20220706132729-d86698d07c53/go.mod h1:KEWEmljWE5zPzLBa/oHl6DaEt9LmfH6WtH1OHIvleBA=
|
google.golang.org/genproto v0.0.0-20220812140447-cec7f5303424/go.mod h1:dbqgFATTzChvnt+ujMdZwITVAJHFtfyN1qUhDqEiIlk=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
|
@ -1068,8 +1060,9 @@ google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
|
||||||
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
|
||||||
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc v1.47.0 h1:9n77onPX5F3qfFCqjy9dhn8PbNQsIKeVU04J9G7umt8=
|
|
||||||
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
google.golang.org/grpc v1.47.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
|
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
|
||||||
|
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
|
||||||
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||||
|
@ -1084,8 +1077,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
|
|
||||||
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
|
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||||
|
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
|
@ -1109,13 +1103,14 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||||
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||||
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
lukechampine.com/uint128 v1.2.0 h1:mBi/5l91vocEN8otkC5bDLhi2KdCticRiwbdB0O+rjI=
|
||||||
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
lukechampine.com/uint128 v1.2.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
|
||||||
modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo=
|
|
||||||
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
|
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
|
||||||
|
modernc.org/cc/v3 v3.36.1 h1:CICrjwr/1M4+6OQ4HJZ/AHxjcwe67r5vPUF518MkO8A=
|
||||||
|
modernc.org/cc/v3 v3.36.1/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
|
||||||
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
|
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
|
||||||
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
|
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
|
||||||
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
|
|
||||||
modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA=
|
|
||||||
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
|
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
|
||||||
|
modernc.org/ccgo/v3 v3.16.8 h1:G0QNlTqI5uVgczBWfGKs7B++EPwCfXPWGD2MdeKloDs=
|
||||||
|
modernc.org/ccgo/v3 v3.16.8/go.mod h1:zNjwkizS+fIFDrDjIAgBSCLkWbJuHF+ar3QRn+Z9aws=
|
||||||
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
|
||||||
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
|
||||||
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
|
||||||
|
@ -1123,9 +1118,9 @@ modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
|
||||||
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
|
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
|
||||||
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
|
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
|
||||||
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
|
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
|
||||||
modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
|
modernc.org/libc v1.16.17/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
|
||||||
modernc.org/libc v1.16.14 h1:MUIjk9Xwlkrp0BqGhMfRkiq0EkZsqfNiP4eixL3YiPk=
|
modernc.org/libc v1.16.19 h1:S8flPn5ZeXx6iw/8yNa986hwTQDrY8RXU7tObZuAozo=
|
||||||
modernc.org/libc v1.16.14/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
|
modernc.org/libc v1.16.19/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
|
||||||
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
|
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
|
||||||
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
|
||||||
|
@ -1134,17 +1129,15 @@ modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
|
||||||
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
|
||||||
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
|
||||||
modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI=
|
modernc.org/sqlite v1.18.1 h1:ko32eKt3jf7eqIkCgPAeHMBXw3riNSLhl2f3loEF7o8=
|
||||||
modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k=
|
modernc.org/sqlite v1.18.1/go.mod h1:6ho+Gow7oX5V+OiOQ6Tr4xeqbx13UZ6t+Fw9IRUG4d4=
|
||||||
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
|
||||||
modernc.org/strutil v1.1.2 h1:iFBDH6j1Z0bN/Q9udJnnFoFpENA4252qe/7/5woE5MI=
|
modernc.org/strutil v1.1.2 h1:iFBDH6j1Z0bN/Q9udJnnFoFpENA4252qe/7/5woE5MI=
|
||||||
modernc.org/strutil v1.1.2/go.mod h1:OYajnUAcI/MX+XD/Wx7v1bbdvcQSvxgtb0gC+u3d3eg=
|
modernc.org/strutil v1.1.2/go.mod h1:OYajnUAcI/MX+XD/Wx7v1bbdvcQSvxgtb0gC+u3d3eg=
|
||||||
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
|
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
|
||||||
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
|
|
||||||
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
|
||||||
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
|
||||||
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
|
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
|
||||||
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
|
|
||||||
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||||
|
|
|
@ -3,12 +3,12 @@ package mails
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/mails/templates"
|
"github.com/pocketbase/pocketbase/mails/templates"
|
||||||
"github.com/pocketbase/pocketbase/models"
|
"github.com/pocketbase/pocketbase/models"
|
||||||
"github.com/pocketbase/pocketbase/tokens"
|
"github.com/pocketbase/pocketbase/tokens"
|
||||||
|
"github.com/pocketbase/pocketbase/tools/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SendAdminPasswordReset sends a password reset request email to the specified admin.
|
// SendAdminPasswordReset sends a password reset request email to the specified admin.
|
||||||
|
@ -18,9 +18,9 @@ func SendAdminPasswordReset(app core.App, admin *models.Admin) error {
|
||||||
return tokenErr
|
return tokenErr
|
||||||
}
|
}
|
||||||
|
|
||||||
actionUrl, urlErr := normalizeUrl(fmt.Sprintf(
|
actionUrl, urlErr := rest.NormalizeUrl(fmt.Sprintf(
|
||||||
"%s/_/#/confirm-password-reset/%s",
|
"%s/_/#/confirm-password-reset/%s",
|
||||||
strings.TrimSuffix(app.Settings().Meta.AppUrl, "/"),
|
app.Settings().Meta.AppUrl,
|
||||||
token,
|
token,
|
||||||
))
|
))
|
||||||
if urlErr != nil {
|
if urlErr != nil {
|
||||||
|
|
|
@ -4,34 +4,9 @@ package mails
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"net/url"
|
|
||||||
"path"
|
|
||||||
"strings"
|
|
||||||
"text/template"
|
"text/template"
|
||||||
)
|
)
|
||||||
|
|
||||||
// normalizeUrl removes duplicated slashes from a url path.
|
|
||||||
func normalizeUrl(originalUrl string) (string, error) {
|
|
||||||
u, err := url.Parse(originalUrl)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
hasSlash := strings.HasSuffix(u.Path, "/")
|
|
||||||
|
|
||||||
// clean up path by removing duplicated /
|
|
||||||
u.Path = path.Clean(u.Path)
|
|
||||||
u.RawPath = path.Clean(u.RawPath)
|
|
||||||
|
|
||||||
// restore original trailing slash
|
|
||||||
if hasSlash && !strings.HasSuffix(u.Path, "/") {
|
|
||||||
u.Path += "/"
|
|
||||||
u.RawPath += "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
return u.String(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// resolveTemplateContent resolves inline html template strings.
|
// resolveTemplateContent resolves inline html template strings.
|
||||||
func resolveTemplateContent(data any, content ...string) (string, error) {
|
func resolveTemplateContent(data any, content ...string) (string, error) {
|
||||||
if len(content) == 0 {
|
if len(content) == 0 {
|
||||||
|
|
|
@ -17,7 +17,6 @@ const AdminPasswordResetBody = `
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Reset password</a>
|
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Reset password</a>
|
||||||
<a class="fallback-link" href="{{.ActionUrl}}" target="_blank" rel="noopener">{{.ActionUrl}}</a>
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p><i>If you did not request to reset your password, please ignore this email and the link will expire on its own.</i></p>
|
<p><i>If you did not request to reset your password, please ignore this email and the link will expire on its own.</i></p>
|
||||||
|
|
|
@ -50,12 +50,6 @@ const Layout = `
|
||||||
.hidden {
|
.hidden {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
.fallback-link {
|
|
||||||
display: none !important;
|
|
||||||
word-break: break-all;
|
|
||||||
font-size: 11px;
|
|
||||||
color: #666f75;
|
|
||||||
}
|
|
||||||
.btn {
|
.btn {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package templates
|
|
||||||
|
|
||||||
// Available variables:
|
|
||||||
//
|
|
||||||
// ```
|
|
||||||
// User *models.User
|
|
||||||
// AppName string
|
|
||||||
// AppUrl string
|
|
||||||
// Token string
|
|
||||||
// ActionUrl string
|
|
||||||
// ```
|
|
||||||
const UserConfirmEmailChangeBody = `
|
|
||||||
{{define "content"}}
|
|
||||||
<p>Hello,</p>
|
|
||||||
<p>Click on the button below to confirm your new email address.</p>
|
|
||||||
<p>
|
|
||||||
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Confirm new email</a>
|
|
||||||
<a class="fallback-link" href="{{.ActionUrl}}" target="_blank" rel="noopener">{{.ActionUrl}}</a>
|
|
||||||
</p>
|
|
||||||
<p><i>If you didn’t ask to change your email address, you can ignore this email.</i></p>
|
|
||||||
<p>
|
|
||||||
Thanks,<br/>
|
|
||||||
{{.AppName}} team
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
`
|
|
|
@ -1,26 +0,0 @@
|
||||||
package templates
|
|
||||||
|
|
||||||
// Available variables:
|
|
||||||
//
|
|
||||||
// ```
|
|
||||||
// User *models.User
|
|
||||||
// AppName string
|
|
||||||
// AppUrl string
|
|
||||||
// Token string
|
|
||||||
// ActionUrl string
|
|
||||||
// ```
|
|
||||||
const UserPasswordResetBody = `
|
|
||||||
{{define "content"}}
|
|
||||||
<p>Hello,</p>
|
|
||||||
<p>Click on the button below to reset your password.</p>
|
|
||||||
<p>
|
|
||||||
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Reset password</a>
|
|
||||||
<a class="fallback-link" href="{{.ActionUrl}}" target="_blank" rel="noopener">{{.ActionUrl}}</a>
|
|
||||||
</p>
|
|
||||||
<p><i>If you didn’t ask to reset your password, you can ignore this email.</i></p>
|
|
||||||
<p>
|
|
||||||
Thanks,<br/>
|
|
||||||
{{.AppName}} team
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
`
|
|
|
@ -1,26 +0,0 @@
|
||||||
package templates
|
|
||||||
|
|
||||||
// Available variables:
|
|
||||||
//
|
|
||||||
// ```
|
|
||||||
// User *models.User
|
|
||||||
// AppName string
|
|
||||||
// AppUrl string
|
|
||||||
// Token string
|
|
||||||
// ActionUrl string
|
|
||||||
// ```
|
|
||||||
const UserVerificationBody = `
|
|
||||||
{{define "content"}}
|
|
||||||
<p>Hello,</p>
|
|
||||||
<p>Thank you for joining us at {{.AppName}}.</p>
|
|
||||||
<p>Click on the button below to verify your email address.</p>
|
|
||||||
<p>
|
|
||||||
<a class="btn" href="{{.ActionUrl}}" target="_blank" rel="noopener">Verify</a>
|
|
||||||
<a class="fallback-link" href="{{.ActionUrl}}" target="_blank" rel="noopener">{{.ActionUrl}}</a>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Thanks,<br/>
|
|
||||||
{{.AppName}} team
|
|
||||||
</p>
|
|
||||||
{{end}}
|
|
||||||
`
|
|
117
mails/user.go
117
mails/user.go
|
@ -1,8 +1,8 @@
|
||||||
package mails
|
package mails
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"html/template"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/mails/templates"
|
"github.com/pocketbase/pocketbase/mails/templates"
|
||||||
|
@ -10,46 +10,6 @@ import (
|
||||||
"github.com/pocketbase/pocketbase/tokens"
|
"github.com/pocketbase/pocketbase/tokens"
|
||||||
)
|
)
|
||||||
|
|
||||||
func prepareUserEmailBody(
|
|
||||||
app core.App,
|
|
||||||
user *models.User,
|
|
||||||
token string,
|
|
||||||
actionUrl string,
|
|
||||||
bodyTemplate string,
|
|
||||||
) (string, error) {
|
|
||||||
settings := app.Settings()
|
|
||||||
|
|
||||||
// replace action url placeholder params (if any)
|
|
||||||
actionUrlParams := map[string]string{
|
|
||||||
core.EmailPlaceholderAppUrl: settings.Meta.AppUrl,
|
|
||||||
core.EmailPlaceholderToken: token,
|
|
||||||
}
|
|
||||||
for k, v := range actionUrlParams {
|
|
||||||
actionUrl = strings.ReplaceAll(actionUrl, k, v)
|
|
||||||
}
|
|
||||||
var urlErr error
|
|
||||||
actionUrl, urlErr = normalizeUrl(actionUrl)
|
|
||||||
if urlErr != nil {
|
|
||||||
return "", urlErr
|
|
||||||
}
|
|
||||||
|
|
||||||
params := struct {
|
|
||||||
AppName string
|
|
||||||
AppUrl string
|
|
||||||
User *models.User
|
|
||||||
Token string
|
|
||||||
ActionUrl string
|
|
||||||
}{
|
|
||||||
AppName: settings.Meta.AppName,
|
|
||||||
AppUrl: settings.Meta.AppUrl,
|
|
||||||
User: user,
|
|
||||||
Token: token,
|
|
||||||
ActionUrl: actionUrl,
|
|
||||||
}
|
|
||||||
|
|
||||||
return resolveTemplateContent(params, templates.Layout, bodyTemplate)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SendUserPasswordReset sends a password reset request email to the specified user.
|
// SendUserPasswordReset sends a password reset request email to the specified user.
|
||||||
func SendUserPasswordReset(app core.App, user *models.User) error {
|
func SendUserPasswordReset(app core.App, user *models.User) error {
|
||||||
token, tokenErr := tokens.NewUserResetPasswordToken(app, user)
|
token, tokenErr := tokens.NewUserResetPasswordToken(app, user)
|
||||||
|
@ -66,24 +26,20 @@ func SendUserPasswordReset(app core.App, user *models.User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendErr := app.OnMailerBeforeUserResetPasswordSend().Trigger(event, func(e *core.MailerUserEvent) error {
|
sendErr := app.OnMailerBeforeUserResetPasswordSend().Trigger(event, func(e *core.MailerUserEvent) error {
|
||||||
body, err := prepareUserEmailBody(
|
settings := app.Settings()
|
||||||
app,
|
|
||||||
user,
|
subject, body, err := resolveEmailTemplate(app, token, settings.Meta.ResetPasswordTemplate)
|
||||||
token,
|
|
||||||
app.Settings().Meta.UserResetPasswordUrl,
|
|
||||||
templates.UserPasswordResetBody,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.MailClient.Send(
|
return e.MailClient.Send(
|
||||||
mail.Address{
|
mail.Address{
|
||||||
Name: app.Settings().Meta.SenderName,
|
Name: settings.Meta.SenderName,
|
||||||
Address: app.Settings().Meta.SenderAddress,
|
Address: settings.Meta.SenderAddress,
|
||||||
},
|
},
|
||||||
mail.Address{Address: e.User.Email},
|
mail.Address{Address: e.User.Email},
|
||||||
("Reset your " + app.Settings().Meta.AppName + " password"),
|
subject,
|
||||||
body,
|
body,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
@ -112,24 +68,20 @@ func SendUserVerification(app core.App, user *models.User) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
sendErr := app.OnMailerBeforeUserVerificationSend().Trigger(event, func(e *core.MailerUserEvent) error {
|
sendErr := app.OnMailerBeforeUserVerificationSend().Trigger(event, func(e *core.MailerUserEvent) error {
|
||||||
body, err := prepareUserEmailBody(
|
settings := app.Settings()
|
||||||
app,
|
|
||||||
user,
|
subject, body, err := resolveEmailTemplate(app, token, settings.Meta.VerificationTemplate)
|
||||||
token,
|
|
||||||
app.Settings().Meta.UserVerificationUrl,
|
|
||||||
templates.UserVerificationBody,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.MailClient.Send(
|
return e.MailClient.Send(
|
||||||
mail.Address{
|
mail.Address{
|
||||||
Name: app.Settings().Meta.SenderName,
|
Name: settings.Meta.SenderName,
|
||||||
Address: app.Settings().Meta.SenderAddress,
|
Address: settings.Meta.SenderAddress,
|
||||||
},
|
},
|
||||||
mail.Address{Address: e.User.Email},
|
mail.Address{Address: e.User.Email},
|
||||||
("Verify your " + app.Settings().Meta.AppName + " email"),
|
subject,
|
||||||
body,
|
body,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
@ -161,24 +113,20 @@ func SendUserChangeEmail(app core.App, user *models.User, newEmail string) error
|
||||||
}
|
}
|
||||||
|
|
||||||
sendErr := app.OnMailerBeforeUserChangeEmailSend().Trigger(event, func(e *core.MailerUserEvent) error {
|
sendErr := app.OnMailerBeforeUserChangeEmailSend().Trigger(event, func(e *core.MailerUserEvent) error {
|
||||||
body, err := prepareUserEmailBody(
|
settings := app.Settings()
|
||||||
app,
|
|
||||||
user,
|
subject, body, err := resolveEmailTemplate(app, token, settings.Meta.ConfirmEmailChangeTemplate)
|
||||||
token,
|
|
||||||
app.Settings().Meta.UserConfirmEmailChangeUrl,
|
|
||||||
templates.UserConfirmEmailChangeBody,
|
|
||||||
)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return e.MailClient.Send(
|
return e.MailClient.Send(
|
||||||
mail.Address{
|
mail.Address{
|
||||||
Name: app.Settings().Meta.SenderName,
|
Name: settings.Meta.SenderName,
|
||||||
Address: app.Settings().Meta.SenderAddress,
|
Address: settings.Meta.SenderAddress,
|
||||||
},
|
},
|
||||||
mail.Address{Address: newEmail},
|
mail.Address{Address: newEmail},
|
||||||
("Confirm your " + app.Settings().Meta.AppName + " new email address"),
|
subject,
|
||||||
body,
|
body,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
|
@ -190,3 +138,30 @@ func SendUserChangeEmail(app core.App, user *models.User, newEmail string) error
|
||||||
|
|
||||||
return sendErr
|
return sendErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveEmailTemplate(
|
||||||
|
app core.App,
|
||||||
|
token string,
|
||||||
|
emailTemplate core.EmailTemplate,
|
||||||
|
) (subject string, body string, err error) {
|
||||||
|
settings := app.Settings()
|
||||||
|
|
||||||
|
subject, rawBody, _ := emailTemplate.Resolve(
|
||||||
|
settings.Meta.AppName,
|
||||||
|
settings.Meta.AppUrl,
|
||||||
|
token,
|
||||||
|
)
|
||||||
|
|
||||||
|
params := struct {
|
||||||
|
HtmlContent template.HTML
|
||||||
|
}{
|
||||||
|
HtmlContent: template.HTML(rawBody),
|
||||||
|
}
|
||||||
|
|
||||||
|
body, err = resolveTemplateContent(params, templates.Layout, templates.HtmlBody)
|
||||||
|
if err != nil {
|
||||||
|
return "", "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return subject, body, nil
|
||||||
|
}
|
||||||
|
|
|
@ -27,7 +27,7 @@ func TestSendUserPasswordReset(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedParts := []string{
|
expectedParts := []string{
|
||||||
"http://localhost:8090/#/users/confirm-password-reset/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",
|
"http://localhost:8090/_/#/users/confirm-password-reset/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",
|
||||||
}
|
}
|
||||||
for _, part := range expectedParts {
|
for _, part := range expectedParts {
|
||||||
if !strings.Contains(testApp.TestMailer.LastHtmlBody, part) {
|
if !strings.Contains(testApp.TestMailer.LastHtmlBody, part) {
|
||||||
|
@ -52,7 +52,7 @@ func TestSendUserVerification(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedParts := []string{
|
expectedParts := []string{
|
||||||
"http://localhost:8090/#/users/confirm-verification/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",
|
"http://localhost:8090/_/#/users/confirm-verification/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",
|
||||||
}
|
}
|
||||||
for _, part := range expectedParts {
|
for _, part := range expectedParts {
|
||||||
if !strings.Contains(testApp.TestMailer.LastHtmlBody, part) {
|
if !strings.Contains(testApp.TestMailer.LastHtmlBody, part) {
|
||||||
|
@ -77,7 +77,7 @@ func TestSendUserChangeEmail(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expectedParts := []string{
|
expectedParts := []string{
|
||||||
"http://localhost:8090/#/users/confirm-email-change/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",
|
"http://localhost:8090/_/#/users/confirm-email-change/eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.",
|
||||||
}
|
}
|
||||||
for _, part := range expectedParts {
|
for _, part := range expectedParts {
|
||||||
if !strings.Contains(testApp.TestMailer.LastHtmlBody, part) {
|
if !strings.Contains(testApp.TestMailer.LastHtmlBody, part) {
|
||||||
|
|
|
@ -9,8 +9,13 @@ import (
|
||||||
"golang.org/x/crypto/bcrypt"
|
"golang.org/x/crypto/bcrypt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultIdLength is the default length of the generated model id.
|
const (
|
||||||
const DefaultIdLength = 15
|
// DefaultIdLength is the default length of the generated model id.
|
||||||
|
DefaultIdLength = 15
|
||||||
|
|
||||||
|
// DefaultIdAlphabet is the default characters set used for generating the model id.
|
||||||
|
DefaultIdAlphabet = "abcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
)
|
||||||
|
|
||||||
// ColumnValueMapper defines an interface for custom db model data serialization.
|
// ColumnValueMapper defines an interface for custom db model data serialization.
|
||||||
type ColumnValueMapper interface {
|
type ColumnValueMapper interface {
|
||||||
|
@ -98,7 +103,7 @@ func (m *BaseModel) GetUpdated() types.DateTime {
|
||||||
//
|
//
|
||||||
// The generated id is a cryptographically random 15 characters length string.
|
// The generated id is a cryptographically random 15 characters length string.
|
||||||
func (m *BaseModel) RefreshId() {
|
func (m *BaseModel) RefreshId() {
|
||||||
m.Id = security.RandomString(DefaultIdLength)
|
m.Id = security.RandomStringWithAlphabet(DefaultIdLength, DefaultIdAlphabet)
|
||||||
}
|
}
|
||||||
|
|
||||||
// RefreshCreated updates the model Created field with the current datetime.
|
// RefreshCreated updates the model Created field with the current datetime.
|
||||||
|
|
Binary file not shown.
|
@ -5,18 +5,12 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"net/mail"
|
"net/mail"
|
||||||
"net/smtp"
|
"net/smtp"
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/domodwyer/mailyak/v3"
|
"github.com/domodwyer/mailyak/v3"
|
||||||
"github.com/microcosm-cc/bluemonday"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var _ Mailer = (*SmtpClient)(nil)
|
var _ Mailer = (*SmtpClient)(nil)
|
||||||
|
|
||||||
// regex to select all tabs
|
|
||||||
var tabsRegex = regexp.MustCompile(`\t+`)
|
|
||||||
|
|
||||||
// NewSmtpClient creates new `SmtpClient` with the provided configuration.
|
// NewSmtpClient creates new `SmtpClient` with the provided configuration.
|
||||||
func NewSmtpClient(
|
func NewSmtpClient(
|
||||||
host string,
|
host string,
|
||||||
|
@ -74,10 +68,6 @@ func (m *SmtpClient) Send(
|
||||||
yak.Subject(subject)
|
yak.Subject(subject)
|
||||||
yak.HTML().Set(htmlBody)
|
yak.HTML().Set(htmlBody)
|
||||||
|
|
||||||
// set also plain text content
|
|
||||||
policy := bluemonday.StrictPolicy() // strips all tags
|
|
||||||
yak.Plain().Set(strings.TrimSpace(tabsRegex.ReplaceAllString(policy.Sanitize(htmlBody), "")))
|
|
||||||
|
|
||||||
for name, data := range attachments {
|
for name, data := range attachments {
|
||||||
yak.Attach(name, data)
|
yak.Attach(name, data)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
package rest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
"path"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// NormalizeUrl removes duplicated slashes from a url path.
|
||||||
|
func NormalizeUrl(originalUrl string) (string, error) {
|
||||||
|
u, err := url.Parse(originalUrl)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
hasSlash := strings.HasSuffix(u.Path, "/")
|
||||||
|
|
||||||
|
// clean up path by removing duplicated /
|
||||||
|
u.Path = path.Clean(u.Path)
|
||||||
|
u.RawPath = path.Clean(u.RawPath)
|
||||||
|
|
||||||
|
// restore original trailing slash
|
||||||
|
if hasSlash && !strings.HasSuffix(u.Path, "/") {
|
||||||
|
u.Path += "/"
|
||||||
|
u.RawPath += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
return u.String(), nil
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package rest_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/pocketbase/pocketbase/tools/rest"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNormalizeUrl(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
url string
|
||||||
|
expectError bool
|
||||||
|
expectUrl string
|
||||||
|
}{
|
||||||
|
{":/", true, ""},
|
||||||
|
{"./", false, "./"},
|
||||||
|
{"../../test////", false, "../../test/"},
|
||||||
|
{"/a/b/c", false, "/a/b/c"},
|
||||||
|
{"a/////b//c/", false, "a/b/c/"},
|
||||||
|
{"/a/////b//c", false, "/a/b/c"},
|
||||||
|
{"///a/b/c", false, "/a/b/c"},
|
||||||
|
{"//a/b/c", false, "//a/b/c"}, // preserve "auto-schema"
|
||||||
|
{"http://a/b/c", false, "http://a/b/c"},
|
||||||
|
{"a//bc?test=1//dd", false, "a/bc?test=1//dd"}, // only the path is normalized
|
||||||
|
{"a//bc?test=1#12///3", false, "a/bc?test=1#12///3"}, // only the path is normalized
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
result, err := rest.NormalizeUrl(s.url)
|
||||||
|
|
||||||
|
hasErr := err != nil
|
||||||
|
if hasErr != s.expectError {
|
||||||
|
t.Errorf("(%d) Expected hasErr %v, got %v", i, s.expectError, hasErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if result != s.expectUrl {
|
||||||
|
t.Errorf("(%d) Expected url %q, got %q", i, s.expectUrl, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,15 +4,23 @@ import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RandomString generates a random string of specified length.
|
// RandomString generates a random string with the specified length.
|
||||||
//
|
//
|
||||||
// The generated string is cryptographically random and matches
|
// The generated string is cryptographically random and matches
|
||||||
// [A-Za-z0-9]+ (aka. it's transparent to URL-encoding).
|
// [A-Za-z0-9]+ (aka. it's transparent to URL-encoding).
|
||||||
func RandomString(length int) string {
|
func RandomString(length int) string {
|
||||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
|
||||||
|
return RandomStringWithAlphabet(length, alphabet)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RandomStringWithAlphabet generates a cryptographically random string
|
||||||
|
// with the specified length and characters set.
|
||||||
|
func RandomStringWithAlphabet(length int, alphabet string) string {
|
||||||
bytes := make([]byte, length)
|
bytes := make([]byte, length)
|
||||||
|
|
||||||
rand.Read(bytes)
|
rand.Read(bytes)
|
||||||
|
|
||||||
for i, b := range bytes {
|
for i, b := range bytes {
|
||||||
bytes[i] = alphabet[b%byte(len(alphabet))]
|
bytes[i] = alphabet[b%byte(len(alphabet))]
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,25 +10,62 @@ import (
|
||||||
func TestRandomString(t *testing.T) {
|
func TestRandomString(t *testing.T) {
|
||||||
generated := []string{}
|
generated := []string{}
|
||||||
reg := regexp.MustCompile(`[a-zA-Z0-9]+`)
|
reg := regexp.MustCompile(`[a-zA-Z0-9]+`)
|
||||||
|
length := 10
|
||||||
|
|
||||||
for i := 0; i < 30; i++ {
|
for i := 0; i < 100; i++ {
|
||||||
length := 5 + i
|
|
||||||
result := security.RandomString(length)
|
result := security.RandomString(length)
|
||||||
|
|
||||||
if len(result) != length {
|
if len(result) != length {
|
||||||
t.Errorf("(%d) Expected the length of the string to be %d, got %d", i, length, len(result))
|
t.Fatalf("(%d) Expected the length of the string to be %d, got %d", i, length, len(result))
|
||||||
}
|
}
|
||||||
|
|
||||||
if match := reg.MatchString(result); !match {
|
if match := reg.MatchString(result); !match {
|
||||||
t.Errorf("(%d) The generated strings should have only [a-zA-Z0-9]+ characters, got %q", i, result)
|
t.Fatalf("(%d) The generated string should have only [a-zA-Z0-9]+ characters, got %q", i, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, str := range generated {
|
for _, str := range generated {
|
||||||
if str == result {
|
if str == result {
|
||||||
t.Errorf("(%d) Repeating random string - found %q in \n%v", i, result, generated)
|
t.Fatalf("(%d) Repeating random string - found %q in \n%v", i, result, generated)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
generated = append(generated, result)
|
generated = append(generated, result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRandomStringWithAlphabet(t *testing.T) {
|
||||||
|
scenarios := []struct {
|
||||||
|
alphabet string
|
||||||
|
expectPattern string
|
||||||
|
}{
|
||||||
|
{"0123456789_", `[0-9_]+`},
|
||||||
|
{"abcd", `[abcd]+`},
|
||||||
|
{"!@#$%^&*()", `[\!\@\#\$\%\^\&\*\(\)]+`},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, s := range scenarios {
|
||||||
|
generated := make([]string, 100)
|
||||||
|
length := 10
|
||||||
|
|
||||||
|
for j := 0; j < 100; j++ {
|
||||||
|
result := security.RandomStringWithAlphabet(length, s.alphabet)
|
||||||
|
|
||||||
|
if len(result) != length {
|
||||||
|
t.Fatalf("(%d:%d) Expected the length of the string to be %d, got %d", i, j, length, len(result))
|
||||||
|
}
|
||||||
|
|
||||||
|
reg := regexp.MustCompile(s.expectPattern)
|
||||||
|
if match := reg.MatchString(result); !match {
|
||||||
|
t.Fatalf("(%d:%d) The generated string should have only %s characters, got %q", i, j, s.expectPattern, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, str := range generated {
|
||||||
|
if str == result {
|
||||||
|
t.Fatalf("(%d:%d) Repeating random string - found %q in %q", i, j, result, generated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
generated = append(generated, result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -27,6 +27,9 @@ func (b *Broker) Clients() map[string]Client {
|
||||||
//
|
//
|
||||||
// Returns non-nil error when client with clientId is not registered.
|
// Returns non-nil error when client with clientId is not registered.
|
||||||
func (b *Broker) ClientById(clientId string) (Client, error) {
|
func (b *Broker) ClientById(clientId string) (Client, error) {
|
||||||
|
b.mux.RLock()
|
||||||
|
defer b.mux.RUnlock()
|
||||||
|
|
||||||
client, ok := b.clients[clientId]
|
client, ok := b.clients[clientId]
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, fmt.Errorf("No client associated with connection ID %q", clientId)
|
return nil, fmt.Errorf("No client associated with connection ID %q", clientId)
|
||||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,2 +1,2 @@
|
||||||
import{S as E,i as G,s as I,F as K,c as A,m as B,t as H,a as N,d as T,C as M,q as J,e as c,w as q,b as k,f as u,r as L,g as b,h as _,u as h,v as O,j as Q,l as U,o as w,A as V,p as W,B as X,D as Y,x as Z,z as S}from"./index.02c04c04.js";function y(f){let e,o,s;return{c(){e=q("for "),o=c("strong"),s=q(f[3]),u(o,"class","txt-nowrap")},m(l,t){b(l,e,t),b(l,o,t),_(o,s)},p(l,t){t&8&&Z(s,l[3])},d(l){l&&w(e),l&&w(o)}}}function x(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0,t.autofocus=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[0]),t.focus(),p||(d=h(t,"input",f[6]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&1&&t.value!==n[0]&&S(t,n[0])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function ee(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password confirm"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[1]),p||(d=h(t,"input",f[7]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&2&&t.value!==n[1]&&S(t,n[1])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function te(f){let e,o,s,l,t,r,p,d,n,i,g,R,C,v,P,F,j,m=f[3]&&y(f);return r=new J({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),d=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),{c(){e=c("form"),o=c("div"),s=c("h4"),l=q(`Reset your admin password
|
import{S as E,i as G,s as I,F as K,c as A,m as B,t as H,a as N,d as T,C as M,q as J,e as c,w as q,b as k,f as u,r as L,g as b,h as _,u as h,v as O,j as Q,l as U,o as w,A as V,p as W,B as X,D as Y,x as Z,z as S}from"./index.46d73605.js";function y(f){let e,o,s;return{c(){e=q("for "),o=c("strong"),s=q(f[3]),u(o,"class","txt-nowrap")},m(l,t){b(l,e,t),b(l,o,t),_(o,s)},p(l,t){t&8&&Z(s,l[3])},d(l){l&&w(e),l&&w(o)}}}function x(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0,t.autofocus=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[0]),t.focus(),p||(d=h(t,"input",f[6]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&1&&t.value!==n[0]&&S(t,n[0])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function ee(f){let e,o,s,l,t,r,p,d;return{c(){e=c("label"),o=q("New password confirm"),l=k(),t=c("input"),u(e,"for",s=f[8]),u(t,"type","password"),u(t,"id",r=f[8]),t.required=!0},m(n,i){b(n,e,i),_(e,o),b(n,l,i),b(n,t,i),S(t,f[1]),p||(d=h(t,"input",f[7]),p=!0)},p(n,i){i&256&&s!==(s=n[8])&&u(e,"for",s),i&256&&r!==(r=n[8])&&u(t,"id",r),i&2&&t.value!==n[1]&&S(t,n[1])},d(n){n&&w(e),n&&w(l),n&&w(t),p=!1,d()}}}function te(f){let e,o,s,l,t,r,p,d,n,i,g,R,C,v,P,F,j,m=f[3]&&y(f);return r=new J({props:{class:"form-field required",name:"password",$$slots:{default:[x,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),d=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[ee,({uniqueId:a})=>({8:a}),({uniqueId:a})=>a?256:0]},$$scope:{ctx:f}}}),{c(){e=c("form"),o=c("div"),s=c("h4"),l=q(`Reset your admin password
|
||||||
`),m&&m.c(),t=k(),A(r.$$.fragment),p=k(),A(d.$$.fragment),n=k(),i=c("button"),g=c("span"),g.textContent="Set new password",R=k(),C=c("div"),v=c("a"),v.textContent="Back to login",u(s,"class","m-b-xs"),u(o,"class","content txt-center m-b-sm"),u(g,"class","txt"),u(i,"type","submit"),u(i,"class","btn btn-lg btn-block"),i.disabled=f[2],L(i,"btn-loading",f[2]),u(e,"class","m-b-base"),u(v,"href","/login"),u(v,"class","link-hint"),u(C,"class","content txt-center")},m(a,$){b(a,e,$),_(e,o),_(o,s),_(s,l),m&&m.m(s,null),_(e,t),B(r,e,null),_(e,p),B(d,e,null),_(e,n),_(e,i),_(i,g),b(a,R,$),b(a,C,$),_(C,v),P=!0,F||(j=[h(e,"submit",O(f[4])),Q(U.call(null,v))],F=!0)},p(a,$){a[3]?m?m.p(a,$):(m=y(a),m.c(),m.m(s,null)):m&&(m.d(1),m=null);const z={};$&769&&(z.$$scope={dirty:$,ctx:a}),r.$set(z);const D={};$&770&&(D.$$scope={dirty:$,ctx:a}),d.$set(D),(!P||$&4)&&(i.disabled=a[2]),$&4&&L(i,"btn-loading",a[2])},i(a){P||(H(r.$$.fragment,a),H(d.$$.fragment,a),P=!0)},o(a){N(r.$$.fragment,a),N(d.$$.fragment,a),P=!1},d(a){a&&w(e),m&&m.d(),T(r),T(d),a&&w(R),a&&w(C),F=!1,V(j)}}}function se(f){let e,o;return e=new K({props:{$$slots:{default:[te]},$$scope:{ctx:f}}}),{c(){A(e.$$.fragment)},m(s,l){B(e,s,l),o=!0},p(s,[l]){const t={};l&527&&(t.$$scope={dirty:l,ctx:s}),e.$set(t)},i(s){o||(H(e.$$.fragment,s),o=!0)},o(s){N(e.$$.fragment,s),o=!1},d(s){T(e,s)}}}function le(f,e,o){let s,{params:l}=e,t="",r="",p=!1;async function d(){if(!p){o(2,p=!0);try{await W.admins.confirmPasswordReset(l==null?void 0:l.token,t,r),X("Successfully set a new admin password."),Y("/")}catch(g){W.errorResponseHandler(g)}o(2,p=!1)}}function n(){t=this.value,o(0,t)}function i(){r=this.value,o(1,r)}return f.$$set=g=>{"params"in g&&o(5,l=g.params)},f.$$.update=()=>{f.$$.dirty&32&&o(3,s=M.getJWTPayload(l==null?void 0:l.token).email||"")},[t,r,p,s,d,l,n,i]}class ae extends E{constructor(e){super(),G(this,e,le,se,I,{params:5})}}export{ae as default};
|
`),m&&m.c(),t=k(),A(r.$$.fragment),p=k(),A(d.$$.fragment),n=k(),i=c("button"),g=c("span"),g.textContent="Set new password",R=k(),C=c("div"),v=c("a"),v.textContent="Back to login",u(s,"class","m-b-xs"),u(o,"class","content txt-center m-b-sm"),u(g,"class","txt"),u(i,"type","submit"),u(i,"class","btn btn-lg btn-block"),i.disabled=f[2],L(i,"btn-loading",f[2]),u(e,"class","m-b-base"),u(v,"href","/login"),u(v,"class","link-hint"),u(C,"class","content txt-center")},m(a,$){b(a,e,$),_(e,o),_(o,s),_(s,l),m&&m.m(s,null),_(e,t),B(r,e,null),_(e,p),B(d,e,null),_(e,n),_(e,i),_(i,g),b(a,R,$),b(a,C,$),_(C,v),P=!0,F||(j=[h(e,"submit",O(f[4])),Q(U.call(null,v))],F=!0)},p(a,$){a[3]?m?m.p(a,$):(m=y(a),m.c(),m.m(s,null)):m&&(m.d(1),m=null);const z={};$&769&&(z.$$scope={dirty:$,ctx:a}),r.$set(z);const D={};$&770&&(D.$$scope={dirty:$,ctx:a}),d.$set(D),(!P||$&4)&&(i.disabled=a[2]),$&4&&L(i,"btn-loading",a[2])},i(a){P||(H(r.$$.fragment,a),H(d.$$.fragment,a),P=!0)},o(a){N(r.$$.fragment,a),N(d.$$.fragment,a),P=!1},d(a){a&&w(e),m&&m.d(),T(r),T(d),a&&w(R),a&&w(C),F=!1,V(j)}}}function se(f){let e,o;return e=new K({props:{$$slots:{default:[te]},$$scope:{ctx:f}}}),{c(){A(e.$$.fragment)},m(s,l){B(e,s,l),o=!0},p(s,[l]){const t={};l&527&&(t.$$scope={dirty:l,ctx:s}),e.$set(t)},i(s){o||(H(e.$$.fragment,s),o=!0)},o(s){N(e.$$.fragment,s),o=!1},d(s){T(e,s)}}}function le(f,e,o){let s,{params:l}=e,t="",r="",p=!1;async function d(){if(!p){o(2,p=!0);try{await W.admins.confirmPasswordReset(l==null?void 0:l.token,t,r),X("Successfully set a new admin password."),Y("/")}catch(g){W.errorResponseHandler(g)}o(2,p=!1)}}function n(){t=this.value,o(0,t)}function i(){r=this.value,o(1,r)}return f.$$set=g=>{"params"in g&&o(5,l=g.params)},f.$$.update=()=>{f.$$.dirty&32&&o(3,s=M.getJWTPayload(l==null?void 0:l.token).email||"")},[t,r,p,s,d,l,n,i]}class ae extends E{constructor(e){super(),G(this,e,le,se,I,{params:5})}}export{ae as default};
|
|
@ -1,2 +1,2 @@
|
||||||
import{S as M,i as T,s as j,F as z,c as H,m as L,t as w,a as y,d as S,b as g,e as _,f as p,g as k,h as d,j as A,l as B,k as N,n as D,o as v,p as C,q as G,r as F,u as E,v as I,w as h,x as J,y as P,z as R}from"./index.02c04c04.js";function K(c){let e,s,n,l,t,o,f,m,i,a,b,u;return l=new G({props:{class:"form-field required",name:"email",$$slots:{default:[Q,({uniqueId:r})=>({5:r}),({uniqueId:r})=>r?32:0]},$$scope:{ctx:c}}}),{c(){e=_("form"),s=_("div"),s.innerHTML=`<h4 class="m-b-xs">Forgotten admin password</h4>
|
import{S as M,i as T,s as j,F as z,c as H,m as L,t as w,a as y,d as S,b as g,e as _,f as p,g as k,h as d,j as A,l as B,k as N,n as D,o as v,p as C,q as G,r as F,u as E,v as I,w as h,x as J,y as P,z as R}from"./index.46d73605.js";function K(c){let e,s,n,l,t,o,f,m,i,a,b,u;return l=new G({props:{class:"form-field required",name:"email",$$slots:{default:[Q,({uniqueId:r})=>({5:r}),({uniqueId:r})=>r?32:0]},$$scope:{ctx:c}}}),{c(){e=_("form"),s=_("div"),s.innerHTML=`<h4 class="m-b-xs">Forgotten admin password</h4>
|
||||||
<p>Enter the email associated with your account and we\u2019ll send you a recovery link:</p>`,n=g(),H(l.$$.fragment),t=g(),o=_("button"),f=_("i"),m=g(),i=_("span"),i.textContent="Send recovery link",p(s,"class","content txt-center m-b-sm"),p(f,"class","ri-mail-send-line"),p(i,"class","txt"),p(o,"type","submit"),p(o,"class","btn btn-lg btn-block"),o.disabled=c[1],F(o,"btn-loading",c[1]),p(e,"class","m-b-base")},m(r,$){k(r,e,$),d(e,s),d(e,n),L(l,e,null),d(e,t),d(e,o),d(o,f),d(o,m),d(o,i),a=!0,b||(u=E(e,"submit",I(c[3])),b=!0)},p(r,$){const q={};$&97&&(q.$$scope={dirty:$,ctx:r}),l.$set(q),(!a||$&2)&&(o.disabled=r[1]),$&2&&F(o,"btn-loading",r[1])},i(r){a||(w(l.$$.fragment,r),a=!0)},o(r){y(l.$$.fragment,r),a=!1},d(r){r&&v(e),S(l),b=!1,u()}}}function O(c){let e,s,n,l,t,o,f,m,i;return{c(){e=_("div"),s=_("div"),s.innerHTML='<i class="ri-checkbox-circle-line"></i>',n=g(),l=_("div"),t=_("p"),o=h("Check "),f=_("strong"),m=h(c[0]),i=h(" for the recovery link."),p(s,"class","icon"),p(f,"class","txt-nowrap"),p(l,"class","content"),p(e,"class","alert alert-success")},m(a,b){k(a,e,b),d(e,s),d(e,n),d(e,l),d(l,t),d(t,o),d(t,f),d(f,m),d(t,i)},p(a,b){b&1&&J(m,a[0])},i:P,o:P,d(a){a&&v(e)}}}function Q(c){let e,s,n,l,t,o,f,m;return{c(){e=_("label"),s=h("Email"),l=g(),t=_("input"),p(e,"for",n=c[5]),p(t,"type","email"),p(t,"id",o=c[5]),t.required=!0,t.autofocus=!0},m(i,a){k(i,e,a),d(e,s),k(i,l,a),k(i,t,a),R(t,c[0]),t.focus(),f||(m=E(t,"input",c[4]),f=!0)},p(i,a){a&32&&n!==(n=i[5])&&p(e,"for",n),a&32&&o!==(o=i[5])&&p(t,"id",o),a&1&&t.value!==i[0]&&R(t,i[0])},d(i){i&&v(e),i&&v(l),i&&v(t),f=!1,m()}}}function U(c){let e,s,n,l,t,o,f,m;const i=[O,K],a=[];function b(u,r){return u[2]?0:1}return e=b(c),s=a[e]=i[e](c),{c(){s.c(),n=g(),l=_("div"),t=_("a"),t.textContent="Back to login",p(t,"href","/login"),p(t,"class","link-hint"),p(l,"class","content txt-center")},m(u,r){a[e].m(u,r),k(u,n,r),k(u,l,r),d(l,t),o=!0,f||(m=A(B.call(null,t)),f=!0)},p(u,r){let $=e;e=b(u),e===$?a[e].p(u,r):(N(),y(a[$],1,1,()=>{a[$]=null}),D(),s=a[e],s?s.p(u,r):(s=a[e]=i[e](u),s.c()),w(s,1),s.m(n.parentNode,n))},i(u){o||(w(s),o=!0)},o(u){y(s),o=!1},d(u){a[e].d(u),u&&v(n),u&&v(l),f=!1,m()}}}function V(c){let e,s;return e=new z({props:{$$slots:{default:[U]},$$scope:{ctx:c}}}),{c(){H(e.$$.fragment)},m(n,l){L(e,n,l),s=!0},p(n,[l]){const t={};l&71&&(t.$$scope={dirty:l,ctx:n}),e.$set(t)},i(n){s||(w(e.$$.fragment,n),s=!0)},o(n){y(e.$$.fragment,n),s=!1},d(n){S(e,n)}}}function W(c,e,s){let n="",l=!1,t=!1;async function o(){if(!l){s(1,l=!0);try{await C.admins.requestPasswordReset(n),s(2,t=!0)}catch(m){C.errorResponseHandler(m)}s(1,l=!1)}}function f(){n=this.value,s(0,n)}return[n,l,t,o,f]}class Y extends M{constructor(e){super(),T(this,e,W,V,j,{})}}export{Y as default};
|
<p>Enter the email associated with your account and we\u2019ll send you a recovery link:</p>`,n=g(),H(l.$$.fragment),t=g(),o=_("button"),f=_("i"),m=g(),i=_("span"),i.textContent="Send recovery link",p(s,"class","content txt-center m-b-sm"),p(f,"class","ri-mail-send-line"),p(i,"class","txt"),p(o,"type","submit"),p(o,"class","btn btn-lg btn-block"),o.disabled=c[1],F(o,"btn-loading",c[1]),p(e,"class","m-b-base")},m(r,$){k(r,e,$),d(e,s),d(e,n),L(l,e,null),d(e,t),d(e,o),d(o,f),d(o,m),d(o,i),a=!0,b||(u=E(e,"submit",I(c[3])),b=!0)},p(r,$){const q={};$&97&&(q.$$scope={dirty:$,ctx:r}),l.$set(q),(!a||$&2)&&(o.disabled=r[1]),$&2&&F(o,"btn-loading",r[1])},i(r){a||(w(l.$$.fragment,r),a=!0)},o(r){y(l.$$.fragment,r),a=!1},d(r){r&&v(e),S(l),b=!1,u()}}}function O(c){let e,s,n,l,t,o,f,m,i;return{c(){e=_("div"),s=_("div"),s.innerHTML='<i class="ri-checkbox-circle-line"></i>',n=g(),l=_("div"),t=_("p"),o=h("Check "),f=_("strong"),m=h(c[0]),i=h(" for the recovery link."),p(s,"class","icon"),p(f,"class","txt-nowrap"),p(l,"class","content"),p(e,"class","alert alert-success")},m(a,b){k(a,e,b),d(e,s),d(e,n),d(e,l),d(l,t),d(t,o),d(t,f),d(f,m),d(t,i)},p(a,b){b&1&&J(m,a[0])},i:P,o:P,d(a){a&&v(e)}}}function Q(c){let e,s,n,l,t,o,f,m;return{c(){e=_("label"),s=h("Email"),l=g(),t=_("input"),p(e,"for",n=c[5]),p(t,"type","email"),p(t,"id",o=c[5]),t.required=!0,t.autofocus=!0},m(i,a){k(i,e,a),d(e,s),k(i,l,a),k(i,t,a),R(t,c[0]),t.focus(),f||(m=E(t,"input",c[4]),f=!0)},p(i,a){a&32&&n!==(n=i[5])&&p(e,"for",n),a&32&&o!==(o=i[5])&&p(t,"id",o),a&1&&t.value!==i[0]&&R(t,i[0])},d(i){i&&v(e),i&&v(l),i&&v(t),f=!1,m()}}}function U(c){let e,s,n,l,t,o,f,m;const i=[O,K],a=[];function b(u,r){return u[2]?0:1}return e=b(c),s=a[e]=i[e](c),{c(){s.c(),n=g(),l=_("div"),t=_("a"),t.textContent="Back to login",p(t,"href","/login"),p(t,"class","link-hint"),p(l,"class","content txt-center")},m(u,r){a[e].m(u,r),k(u,n,r),k(u,l,r),d(l,t),o=!0,f||(m=A(B.call(null,t)),f=!0)},p(u,r){let $=e;e=b(u),e===$?a[e].p(u,r):(N(),y(a[$],1,1,()=>{a[$]=null}),D(),s=a[e],s?s.p(u,r):(s=a[e]=i[e](u),s.c()),w(s,1),s.m(n.parentNode,n))},i(u){o||(w(s),o=!0)},o(u){y(s),o=!1},d(u){a[e].d(u),u&&v(n),u&&v(l),f=!1,m()}}}function V(c){let e,s;return e=new z({props:{$$slots:{default:[U]},$$scope:{ctx:c}}}),{c(){H(e.$$.fragment)},m(n,l){L(e,n,l),s=!0},p(n,[l]){const t={};l&71&&(t.$$scope={dirty:l,ctx:n}),e.$set(t)},i(n){s||(w(e.$$.fragment,n),s=!0)},o(n){y(e.$$.fragment,n),s=!1},d(n){S(e,n)}}}function W(c,e,s){let n="",l=!1,t=!1;async function o(){if(!l){s(1,l=!0);try{await C.admins.requestPasswordReset(n),s(2,t=!0)}catch(m){C.errorResponseHandler(m)}s(1,l=!1)}}function f(){n=this.value,s(0,n)}return[n,l,t,o,f]}class Y extends M{constructor(e){super(),T(this,e,W,V,j,{})}}export{Y as default};
|
|
@ -1,4 +1,4 @@
|
||||||
import{S as M,i as N,s as R,F as U,c as S,m as z,t as $,a as v,d as J,C as W,E as Y,g as _,k as j,n as A,o as b,p as F,q as B,e as m,w as y,b as C,f as d,r as H,h as k,u as E,v as D,y as h,x as G,z as T}from"./index.02c04c04.js";function I(r){let e,s,t,l,n,o,c,a,i,u,g,q,p=r[3]&&L(r);return o=new B({props:{class:"form-field required",name:"password",$$slots:{default:[O,({uniqueId:f})=>({8:f}),({uniqueId:f})=>f?256:0]},$$scope:{ctx:r}}}),{c(){e=m("form"),s=m("div"),t=m("h4"),l=y(`Type your password to confirm changing your email address
|
import{S as M,i as N,s as R,F as U,c as L,m as z,t as $,a as v,d as J,C as W,E as Y,g as _,k as j,n as A,o as b,p as F,q as B,e as m,w as y,b as C,f as d,r as H,h as k,u as E,v as D,y as h,x as G,z as S}from"./index.46d73605.js";function I(r){let e,s,t,l,n,o,c,a,i,u,g,q,p=r[3]&&T(r);return o=new B({props:{class:"form-field required",name:"password",$$slots:{default:[O,({uniqueId:f})=>({8:f}),({uniqueId:f})=>f?256:0]},$$scope:{ctx:r}}}),{c(){e=m("form"),s=m("div"),t=m("h4"),l=y(`Type your password to confirm changing your email address
|
||||||
`),p&&p.c(),n=C(),S(o.$$.fragment),c=C(),a=m("button"),i=m("span"),i.textContent="Confirm new email",d(t,"class","m-b-xs"),d(s,"class","content txt-center m-b-sm"),d(i,"class","txt"),d(a,"type","submit"),d(a,"class","btn btn-lg btn-block"),a.disabled=r[1],H(a,"btn-loading",r[1])},m(f,w){_(f,e,w),k(e,s),k(s,t),k(t,l),p&&p.m(t,null),k(e,n),z(o,e,null),k(e,c),k(e,a),k(a,i),u=!0,g||(q=E(e,"submit",D(r[4])),g=!0)},p(f,w){f[3]?p?p.p(f,w):(p=L(f),p.c(),p.m(t,null)):p&&(p.d(1),p=null);const P={};w&769&&(P.$$scope={dirty:w,ctx:f}),o.$set(P),(!u||w&2)&&(a.disabled=f[1]),w&2&&H(a,"btn-loading",f[1])},i(f){u||($(o.$$.fragment,f),u=!0)},o(f){v(o.$$.fragment,f),u=!1},d(f){f&&b(e),p&&p.d(),J(o),g=!1,q()}}}function K(r){let e,s,t,l,n;return{c(){e=m("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
`),p&&p.c(),n=C(),L(o.$$.fragment),c=C(),a=m("button"),i=m("span"),i.textContent="Confirm new email",d(t,"class","m-b-xs"),d(s,"class","content txt-center m-b-sm"),d(i,"class","txt"),d(a,"type","submit"),d(a,"class","btn btn-lg btn-block"),a.disabled=r[1],H(a,"btn-loading",r[1])},m(f,w){_(f,e,w),k(e,s),k(s,t),k(t,l),p&&p.m(t,null),k(e,n),z(o,e,null),k(e,c),k(e,a),k(a,i),u=!0,g||(q=E(e,"submit",D(r[4])),g=!0)},p(f,w){f[3]?p?p.p(f,w):(p=T(f),p.c(),p.m(t,null)):p&&(p.d(1),p=null);const P={};w&769&&(P.$$scope={dirty:w,ctx:f}),o.$set(P),(!u||w&2)&&(a.disabled=f[1]),w&2&&H(a,"btn-loading",f[1])},i(f){u||($(o.$$.fragment,f),u=!0)},o(f){v(o.$$.fragment,f),u=!1},d(f){f&&b(e),p&&p.d(),J(o),g=!1,q()}}}function K(r){let e,s,t,l,n;return{c(){e=m("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
||||||
<div class="content txt-bold"><p>Email address changed</p>
|
<div class="content txt-bold"><p>Successfully changed the user email address.</p>
|
||||||
<p>You can now sign in with your new email address.</p></div>`,s=C(),t=m("button"),t.textContent="Close",d(e,"class","alert alert-success"),d(t,"type","button"),d(t,"class","btn btn-secondary btn-block")},m(o,c){_(o,e,c),_(o,s,c),_(o,t,c),l||(n=E(t,"click",r[6]),l=!0)},p:h,i:h,o:h,d(o){o&&b(e),o&&b(s),o&&b(t),l=!1,n()}}}function L(r){let e,s,t;return{c(){e=y("to "),s=m("strong"),t=y(r[3]),d(s,"class","txt-nowrap")},m(l,n){_(l,e,n),_(l,s,n),k(s,t)},p(l,n){n&8&&G(t,l[3])},d(l){l&&b(e),l&&b(s)}}}function O(r){let e,s,t,l,n,o,c,a;return{c(){e=m("label"),s=y("Password"),l=C(),n=m("input"),d(e,"for",t=r[8]),d(n,"type","password"),d(n,"id",o=r[8]),n.required=!0,n.autofocus=!0},m(i,u){_(i,e,u),k(e,s),_(i,l,u),_(i,n,u),T(n,r[0]),n.focus(),c||(a=E(n,"input",r[7]),c=!0)},p(i,u){u&256&&t!==(t=i[8])&&d(e,"for",t),u&256&&o!==(o=i[8])&&d(n,"id",o),u&1&&n.value!==i[0]&&T(n,i[0])},d(i){i&&b(e),i&&b(l),i&&b(n),c=!1,a()}}}function Q(r){let e,s,t,l;const n=[K,I],o=[];function c(a,i){return a[2]?0:1}return e=c(r),s=o[e]=n[e](r),{c(){s.c(),t=Y()},m(a,i){o[e].m(a,i),_(a,t,i),l=!0},p(a,i){let u=e;e=c(a),e===u?o[e].p(a,i):(j(),v(o[u],1,1,()=>{o[u]=null}),A(),s=o[e],s?s.p(a,i):(s=o[e]=n[e](a),s.c()),$(s,1),s.m(t.parentNode,t))},i(a){l||($(s),l=!0)},o(a){v(s),l=!1},d(a){o[e].d(a),a&&b(t)}}}function V(r){let e,s;return e=new U({props:{nobranding:!0,$$slots:{default:[Q]},$$scope:{ctx:r}}}),{c(){S(e.$$.fragment)},m(t,l){z(e,t,l),s=!0},p(t,[l]){const n={};l&527&&(n.$$scope={dirty:l,ctx:t}),e.$set(n)},i(t){s||($(e.$$.fragment,t),s=!0)},o(t){v(e.$$.fragment,t),s=!1},d(t){J(e,t)}}}function X(r,e,s){let t,{params:l}=e,n="",o=!1,c=!1;async function a(){if(!o){s(1,o=!0);try{await F.users.confirmEmailChange(l==null?void 0:l.token,n),s(2,c=!0)}catch(g){F.errorResponseHandler(g)}s(1,o=!1)}}const i=()=>window.close();function u(){n=this.value,s(0,n)}return r.$$set=g=>{"params"in g&&s(5,l=g.params)},r.$$.update=()=>{r.$$.dirty&32&&s(3,t=W.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[n,o,c,t,a,l,i,u]}class x extends M{constructor(e){super(),N(this,e,X,V,R,{params:5})}}export{x as default};
|
<p>You can now sign in with your new email address.</p></div>`,s=C(),t=m("button"),t.textContent="Close",d(e,"class","alert alert-success"),d(t,"type","button"),d(t,"class","btn btn-secondary btn-block")},m(o,c){_(o,e,c),_(o,s,c),_(o,t,c),l||(n=E(t,"click",r[6]),l=!0)},p:h,i:h,o:h,d(o){o&&b(e),o&&b(s),o&&b(t),l=!1,n()}}}function T(r){let e,s,t;return{c(){e=y("to "),s=m("strong"),t=y(r[3]),d(s,"class","txt-nowrap")},m(l,n){_(l,e,n),_(l,s,n),k(s,t)},p(l,n){n&8&&G(t,l[3])},d(l){l&&b(e),l&&b(s)}}}function O(r){let e,s,t,l,n,o,c,a;return{c(){e=m("label"),s=y("Password"),l=C(),n=m("input"),d(e,"for",t=r[8]),d(n,"type","password"),d(n,"id",o=r[8]),n.required=!0,n.autofocus=!0},m(i,u){_(i,e,u),k(e,s),_(i,l,u),_(i,n,u),S(n,r[0]),n.focus(),c||(a=E(n,"input",r[7]),c=!0)},p(i,u){u&256&&t!==(t=i[8])&&d(e,"for",t),u&256&&o!==(o=i[8])&&d(n,"id",o),u&1&&n.value!==i[0]&&S(n,i[0])},d(i){i&&b(e),i&&b(l),i&&b(n),c=!1,a()}}}function Q(r){let e,s,t,l;const n=[K,I],o=[];function c(a,i){return a[2]?0:1}return e=c(r),s=o[e]=n[e](r),{c(){s.c(),t=Y()},m(a,i){o[e].m(a,i),_(a,t,i),l=!0},p(a,i){let u=e;e=c(a),e===u?o[e].p(a,i):(j(),v(o[u],1,1,()=>{o[u]=null}),A(),s=o[e],s?s.p(a,i):(s=o[e]=n[e](a),s.c()),$(s,1),s.m(t.parentNode,t))},i(a){l||($(s),l=!0)},o(a){v(s),l=!1},d(a){o[e].d(a),a&&b(t)}}}function V(r){let e,s;return e=new U({props:{nobranding:!0,$$slots:{default:[Q]},$$scope:{ctx:r}}}),{c(){L(e.$$.fragment)},m(t,l){z(e,t,l),s=!0},p(t,[l]){const n={};l&527&&(n.$$scope={dirty:l,ctx:t}),e.$set(n)},i(t){s||($(e.$$.fragment,t),s=!0)},o(t){v(e.$$.fragment,t),s=!1},d(t){J(e,t)}}}function X(r,e,s){let t,{params:l}=e,n="",o=!1,c=!1;async function a(){if(!o){s(1,o=!0);try{await F.users.confirmEmailChange(l==null?void 0:l.token,n),s(2,c=!0)}catch(g){F.errorResponseHandler(g)}s(1,o=!1)}}const i=()=>window.close();function u(){n=this.value,s(0,n)}return r.$$set=g=>{"params"in g&&s(5,l=g.params)},r.$$.update=()=>{r.$$.dirty&32&&s(3,t=W.getJWTPayload(l==null?void 0:l.token).newEmail||"")},[n,o,c,t,a,l,i,u]}class x extends M{constructor(e){super(),N(this,e,X,V,R,{params:5})}}export{x as default};
|
|
@ -0,0 +1,4 @@
|
||||||
|
import{S as W,i as Y,s as j,F as A,c as F,m as H,t as P,a as q,d as N,C as B,E as D,g as _,k as G,n as I,o as m,p as E,q as J,e as b,w as y,b as C,f as c,r as M,h as w,u as R,v as K,y as S,x as O,z as h}from"./index.46d73605.js";function Q(i){let e,l,t,n,s,o,p,u,r,a,v,g,k,L,d=i[4]&&U(i);return o=new J({props:{class:"form-field required",name:"password",$$slots:{default:[X,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),u=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[Z,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),{c(){e=b("form"),l=b("div"),t=b("h4"),n=y(`Reset your user password
|
||||||
|
`),d&&d.c(),s=C(),F(o.$$.fragment),p=C(),F(u.$$.fragment),r=C(),a=b("button"),v=b("span"),v.textContent="Set new password",c(t,"class","m-b-xs"),c(l,"class","content txt-center m-b-sm"),c(v,"class","txt"),c(a,"type","submit"),c(a,"class","btn btn-lg btn-block"),a.disabled=i[2],M(a,"btn-loading",i[2])},m(f,$){_(f,e,$),w(e,l),w(l,t),w(t,n),d&&d.m(t,null),w(e,s),H(o,e,null),w(e,p),H(u,e,null),w(e,r),w(e,a),w(a,v),g=!0,k||(L=R(e,"submit",K(i[5])),k=!0)},p(f,$){f[4]?d?d.p(f,$):(d=U(f),d.c(),d.m(t,null)):d&&(d.d(1),d=null);const T={};$&3073&&(T.$$scope={dirty:$,ctx:f}),o.$set(T);const z={};$&3074&&(z.$$scope={dirty:$,ctx:f}),u.$set(z),(!g||$&4)&&(a.disabled=f[2]),$&4&&M(a,"btn-loading",f[2])},i(f){g||(P(o.$$.fragment,f),P(u.$$.fragment,f),g=!0)},o(f){q(o.$$.fragment,f),q(u.$$.fragment,f),g=!1},d(f){f&&m(e),d&&d.d(),N(o),N(u),k=!1,L()}}}function V(i){let e,l,t,n,s;return{c(){e=b("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
||||||
|
<div class="content txt-bold"><p>Successfully changed the user password.</p>
|
||||||
|
<p>You can now sign in with your new password.</p></div>`,l=C(),t=b("button"),t.textContent="Close",c(e,"class","alert alert-success"),c(t,"type","button"),c(t,"class","btn btn-secondary btn-block")},m(o,p){_(o,e,p),_(o,l,p),_(o,t,p),n||(s=R(t,"click",i[7]),n=!0)},p:S,i:S,o:S,d(o){o&&m(e),o&&m(l),o&&m(t),n=!1,s()}}}function U(i){let e,l,t;return{c(){e=y("for "),l=b("strong"),t=y(i[4])},m(n,s){_(n,e,s),_(n,l,s),w(l,t)},p(n,s){s&16&&O(t,n[4])},d(n){n&&m(e),n&&m(l)}}}function X(i){let e,l,t,n,s,o,p,u;return{c(){e=b("label"),l=y("New password"),n=C(),s=b("input"),c(e,"for",t=i[10]),c(s,"type","password"),c(s,"id",o=i[10]),s.required=!0,s.autofocus=!0},m(r,a){_(r,e,a),w(e,l),_(r,n,a),_(r,s,a),h(s,i[0]),s.focus(),p||(u=R(s,"input",i[8]),p=!0)},p(r,a){a&1024&&t!==(t=r[10])&&c(e,"for",t),a&1024&&o!==(o=r[10])&&c(s,"id",o),a&1&&s.value!==r[0]&&h(s,r[0])},d(r){r&&m(e),r&&m(n),r&&m(s),p=!1,u()}}}function Z(i){let e,l,t,n,s,o,p,u;return{c(){e=b("label"),l=y("New password confirm"),n=C(),s=b("input"),c(e,"for",t=i[10]),c(s,"type","password"),c(s,"id",o=i[10]),s.required=!0},m(r,a){_(r,e,a),w(e,l),_(r,n,a),_(r,s,a),h(s,i[1]),p||(u=R(s,"input",i[9]),p=!0)},p(r,a){a&1024&&t!==(t=r[10])&&c(e,"for",t),a&1024&&o!==(o=r[10])&&c(s,"id",o),a&2&&s.value!==r[1]&&h(s,r[1])},d(r){r&&m(e),r&&m(n),r&&m(s),p=!1,u()}}}function x(i){let e,l,t,n;const s=[V,Q],o=[];function p(u,r){return u[3]?0:1}return e=p(i),l=o[e]=s[e](i),{c(){l.c(),t=D()},m(u,r){o[e].m(u,r),_(u,t,r),n=!0},p(u,r){let a=e;e=p(u),e===a?o[e].p(u,r):(G(),q(o[a],1,1,()=>{o[a]=null}),I(),l=o[e],l?l.p(u,r):(l=o[e]=s[e](u),l.c()),P(l,1),l.m(t.parentNode,t))},i(u){n||(P(l),n=!0)},o(u){q(l),n=!1},d(u){o[e].d(u),u&&m(t)}}}function ee(i){let e,l;return e=new A({props:{nobranding:!0,$$slots:{default:[x]},$$scope:{ctx:i}}}),{c(){F(e.$$.fragment)},m(t,n){H(e,t,n),l=!0},p(t,[n]){const s={};n&2079&&(s.$$scope={dirty:n,ctx:t}),e.$set(s)},i(t){l||(P(e.$$.fragment,t),l=!0)},o(t){q(e.$$.fragment,t),l=!1},d(t){N(e,t)}}}function te(i,e,l){let t,{params:n}=e,s="",o="",p=!1,u=!1;async function r(){if(!p){l(2,p=!0);try{await E.users.confirmPasswordReset(n==null?void 0:n.token,s,o),l(3,u=!0)}catch(k){E.errorResponseHandler(k)}l(2,p=!1)}}const a=()=>window.close();function v(){s=this.value,l(0,s)}function g(){o=this.value,l(1,o)}return i.$$set=k=>{"params"in k&&l(6,n=k.params)},i.$$.update=()=>{i.$$.dirty&64&&l(4,t=B.getJWTPayload(n==null?void 0:n.token).email||"")},[s,o,p,u,t,r,n,a,v,g]}class le extends W{constructor(e){super(),Y(this,e,te,ee,j,{params:6})}}export{le as default};
|
|
@ -1,4 +0,0 @@
|
||||||
import{S as W,i as Y,s as j,F as A,c as H,m as N,t as P,a as q,d as S,C as B,E as D,g as _,k as G,n as I,o as m,p as E,q as J,e as b,w as y,b as C,f as c,r as M,h as w,u as h,v as K,y as F,x as O,z as R}from"./index.02c04c04.js";function Q(i){let e,l,t,n,s,o,p,a,r,u,v,g,k,L,d=i[4]&&U(i);return o=new J({props:{class:"form-field required",name:"password",$$slots:{default:[X,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),a=new J({props:{class:"form-field required",name:"passwordConfirm",$$slots:{default:[Z,({uniqueId:f})=>({10:f}),({uniqueId:f})=>f?1024:0]},$$scope:{ctx:i}}}),{c(){e=b("form"),l=b("div"),t=b("h4"),n=y(`Reset your user password
|
|
||||||
`),d&&d.c(),s=C(),H(o.$$.fragment),p=C(),H(a.$$.fragment),r=C(),u=b("button"),v=b("span"),v.textContent="Set new password",c(t,"class","m-b-xs"),c(l,"class","content txt-center m-b-sm"),c(v,"class","txt"),c(u,"type","submit"),c(u,"class","btn btn-lg btn-block"),u.disabled=i[2],M(u,"btn-loading",i[2])},m(f,$){_(f,e,$),w(e,l),w(l,t),w(t,n),d&&d.m(t,null),w(e,s),N(o,e,null),w(e,p),N(a,e,null),w(e,r),w(e,u),w(u,v),g=!0,k||(L=h(e,"submit",K(i[5])),k=!0)},p(f,$){f[4]?d?d.p(f,$):(d=U(f),d.c(),d.m(t,null)):d&&(d.d(1),d=null);const T={};$&3073&&(T.$$scope={dirty:$,ctx:f}),o.$set(T);const z={};$&3074&&(z.$$scope={dirty:$,ctx:f}),a.$set(z),(!g||$&4)&&(u.disabled=f[2]),$&4&&M(u,"btn-loading",f[2])},i(f){g||(P(o.$$.fragment,f),P(a.$$.fragment,f),g=!0)},o(f){q(o.$$.fragment,f),q(a.$$.fragment,f),g=!1},d(f){f&&m(e),d&&d.d(),S(o),S(a),k=!1,L()}}}function V(i){let e,l,t,n,s;return{c(){e=b("div"),e.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
|
||||||
<div class="content txt-bold"><p>Password changed</p>
|
|
||||||
<p>You can now sign in with your new password.</p></div>`,l=C(),t=b("button"),t.textContent="Close",c(e,"class","alert alert-success"),c(t,"type","button"),c(t,"class","btn btn-secondary btn-block")},m(o,p){_(o,e,p),_(o,l,p),_(o,t,p),n||(s=h(t,"click",i[7]),n=!0)},p:F,i:F,o:F,d(o){o&&m(e),o&&m(l),o&&m(t),n=!1,s()}}}function U(i){let e,l,t;return{c(){e=y("for "),l=b("strong"),t=y(i[4])},m(n,s){_(n,e,s),_(n,l,s),w(l,t)},p(n,s){s&16&&O(t,n[4])},d(n){n&&m(e),n&&m(l)}}}function X(i){let e,l,t,n,s,o,p,a;return{c(){e=b("label"),l=y("New password"),n=C(),s=b("input"),c(e,"for",t=i[10]),c(s,"type","password"),c(s,"id",o=i[10]),s.required=!0,s.autofocus=!0},m(r,u){_(r,e,u),w(e,l),_(r,n,u),_(r,s,u),R(s,i[0]),s.focus(),p||(a=h(s,"input",i[8]),p=!0)},p(r,u){u&1024&&t!==(t=r[10])&&c(e,"for",t),u&1024&&o!==(o=r[10])&&c(s,"id",o),u&1&&s.value!==r[0]&&R(s,r[0])},d(r){r&&m(e),r&&m(n),r&&m(s),p=!1,a()}}}function Z(i){let e,l,t,n,s,o,p,a;return{c(){e=b("label"),l=y("New password confirm"),n=C(),s=b("input"),c(e,"for",t=i[10]),c(s,"type","password"),c(s,"id",o=i[10]),s.required=!0},m(r,u){_(r,e,u),w(e,l),_(r,n,u),_(r,s,u),R(s,i[1]),p||(a=h(s,"input",i[9]),p=!0)},p(r,u){u&1024&&t!==(t=r[10])&&c(e,"for",t),u&1024&&o!==(o=r[10])&&c(s,"id",o),u&2&&s.value!==r[1]&&R(s,r[1])},d(r){r&&m(e),r&&m(n),r&&m(s),p=!1,a()}}}function x(i){let e,l,t,n;const s=[V,Q],o=[];function p(a,r){return a[3]?0:1}return e=p(i),l=o[e]=s[e](i),{c(){l.c(),t=D()},m(a,r){o[e].m(a,r),_(a,t,r),n=!0},p(a,r){let u=e;e=p(a),e===u?o[e].p(a,r):(G(),q(o[u],1,1,()=>{o[u]=null}),I(),l=o[e],l?l.p(a,r):(l=o[e]=s[e](a),l.c()),P(l,1),l.m(t.parentNode,t))},i(a){n||(P(l),n=!0)},o(a){q(l),n=!1},d(a){o[e].d(a),a&&m(t)}}}function ee(i){let e,l;return e=new A({props:{nobranding:!0,$$slots:{default:[x]},$$scope:{ctx:i}}}),{c(){H(e.$$.fragment)},m(t,n){N(e,t,n),l=!0},p(t,[n]){const s={};n&2079&&(s.$$scope={dirty:n,ctx:t}),e.$set(s)},i(t){l||(P(e.$$.fragment,t),l=!0)},o(t){q(e.$$.fragment,t),l=!1},d(t){S(e,t)}}}function te(i,e,l){let t,{params:n}=e,s="",o="",p=!1,a=!1;async function r(){if(!p){l(2,p=!0);try{await E.users.confirmPasswordReset(n==null?void 0:n.token,s,o),l(3,a=!0)}catch(k){E.errorResponseHandler(k)}l(2,p=!1)}}const u=()=>window.close();function v(){s=this.value,l(0,s)}function g(){o=this.value,l(1,o)}return i.$$set=k=>{"params"in k&&l(6,n=k.params)},i.$$.update=()=>{i.$$.dirty&64&&l(4,t=B.getJWTPayload(n==null?void 0:n.token).email||"")},[s,o,p,a,t,r,n,u,v,g]}class le extends W{constructor(e){super(),Y(this,e,te,ee,j,{params:6})}}export{le as default};
|
|
|
@ -1,3 +1,3 @@
|
||||||
import{S as k,i as v,s as y,F as w,c as x,m as C,t as g,a as $,d as L,p as H,E as M,g as r,o as a,e as u,b as m,f,u as _,y as p}from"./index.02c04c04.js";function P(o){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-error-warning-line"></i></div>
|
import{S as k,i as v,s as y,F as w,c as x,m as C,t as g,a as $,d as L,p as H,E as M,g as r,o as a,e as u,b as m,f,u as _,y as p}from"./index.46d73605.js";function P(o){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-error-warning-line"></i></div>
|
||||||
<div class="content txt-bold"><p>Invalid or expired verification token.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-danger"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,c){r(l,t,c),r(l,s,c),r(l,e,c),n||(i=_(e,"click",o[4]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function S(o){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
<div class="content txt-bold"><p>Invalid or expired verification token.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-danger"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,c){r(l,t,c),r(l,s,c),r(l,e,c),n||(i=_(e,"click",o[4]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function S(o){let t,s,e,n,i;return{c(){t=u("div"),t.innerHTML=`<div class="icon"><i class="ri-checkbox-circle-line"></i></div>
|
||||||
<div class="content txt-bold"><p>Successfully verified email address.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-success"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,c){r(l,t,c),r(l,s,c),r(l,e,c),n||(i=_(e,"click",o[3]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function T(o){let t;return{c(){t=u("div"),t.innerHTML='<div class="loader loader-lg"><em>Please wait...</em></div>',f(t,"class","txt-center")},m(s,e){r(s,t,e)},p,d(s){s&&a(t)}}}function F(o){let t;function s(i,l){return i[1]?T:i[0]?S:P}let e=s(o),n=e(o);return{c(){n.c(),t=M()},m(i,l){n.m(i,l),r(i,t,l)},p(i,l){e===(e=s(i))&&n?n.p(i,l):(n.d(1),n=e(i),n&&(n.c(),n.m(t.parentNode,t)))},d(i){n.d(i),i&&a(t)}}}function V(o){let t,s;return t=new w({props:{nobranding:!0,$$slots:{default:[F]},$$scope:{ctx:o}}}),{c(){x(t.$$.fragment)},m(e,n){C(t,e,n),s=!0},p(e,[n]){const i={};n&67&&(i.$$scope={dirty:n,ctx:e}),t.$set(i)},i(e){s||(g(t.$$.fragment,e),s=!0)},o(e){$(t.$$.fragment,e),s=!1},d(e){L(t,e)}}}function q(o,t,s){let{params:e}=t,n=!1,i=!1;l();async function l(){s(1,i=!0);try{await H.users.confirmVerification(e==null?void 0:e.token),s(0,n=!0)}catch(d){console.warn(d),s(0,n=!1)}s(1,i=!1)}const c=()=>window.close(),b=()=>window.close();return o.$$set=d=>{"params"in d&&s(2,e=d.params)},[n,i,e,c,b]}class I extends k{constructor(t){super(),v(this,t,q,V,y,{params:2})}}export{I as default};
|
<div class="content txt-bold"><p>Successfully verified email address.</p></div>`,s=m(),e=u("button"),e.textContent="Close",f(t,"class","alert alert-success"),f(e,"type","button"),f(e,"class","btn btn-secondary btn-block")},m(l,c){r(l,t,c),r(l,s,c),r(l,e,c),n||(i=_(e,"click",o[3]),n=!0)},p,d(l){l&&a(t),l&&a(s),l&&a(e),n=!1,i()}}}function T(o){let t;return{c(){t=u("div"),t.innerHTML='<div class="loader loader-lg"><em>Please wait...</em></div>',f(t,"class","txt-center")},m(s,e){r(s,t,e)},p,d(s){s&&a(t)}}}function F(o){let t;function s(i,l){return i[1]?T:i[0]?S:P}let e=s(o),n=e(o);return{c(){n.c(),t=M()},m(i,l){n.m(i,l),r(i,t,l)},p(i,l){e===(e=s(i))&&n?n.p(i,l):(n.d(1),n=e(i),n&&(n.c(),n.m(t.parentNode,t)))},d(i){n.d(i),i&&a(t)}}}function V(o){let t,s;return t=new w({props:{nobranding:!0,$$slots:{default:[F]},$$scope:{ctx:o}}}),{c(){x(t.$$.fragment)},m(e,n){C(t,e,n),s=!0},p(e,[n]){const i={};n&67&&(i.$$scope={dirty:n,ctx:e}),t.$set(i)},i(e){s||(g(t.$$.fragment,e),s=!0)},o(e){$(t.$$.fragment,e),s=!1},d(e){L(t,e)}}}function q(o,t,s){let{params:e}=t,n=!1,i=!1;l();async function l(){s(1,i=!0);try{await H.users.confirmVerification(e==null?void 0:e.token),s(0,n=!0)}catch(d){console.warn(d),s(0,n=!1)}s(1,i=!1)}const c=()=>window.close(),b=()=>window.close();return o.$$set=d=>{"params"in d&&s(2,e=d.params)},[n,i,e,c,b]}class I extends k{constructor(t){super(),v(this,t,q,V,y,{params:2})}}export{I as default};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -24,8 +24,8 @@
|
||||||
window.Prism = window.Prism || {};
|
window.Prism = window.Prism || {};
|
||||||
window.Prism.manual = true;
|
window.Prism.manual = true;
|
||||||
</script>
|
</script>
|
||||||
<script type="module" crossorigin src="./assets/index.02c04c04.js"></script>
|
<script type="module" crossorigin src="./assets/index.46d73605.js"></script>
|
||||||
<link rel="stylesheet" href="./assets/index.3b402ee9.css">
|
<link rel="stylesheet" href="./assets/index.4ad79864.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|
|
@ -28,6 +28,10 @@
|
||||||
export function collapse() {
|
export function collapse() {
|
||||||
accordion?.collapse();
|
accordion?.collapse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function collapseSiblings() {
|
||||||
|
accordion?.collapseSiblings();
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Accordion bind:this={accordion} on:expand on:collapse on:toggle {...$$restProps}>
|
<Accordion bind:this={accordion} on:expand on:collapse on:toggle {...$$restProps}>
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
|
|
||||||
let accordion;
|
let accordion;
|
||||||
|
|
||||||
$: hasErrors = !CommonHelper.isEmpty($errors?.emailPassword);
|
$: hasErrors = !CommonHelper.isEmpty($errors?.emailAuth);
|
||||||
|
|
||||||
export function expand() {
|
export function expand() {
|
||||||
accordion?.expand();
|
accordion?.expand();
|
||||||
|
@ -50,7 +50,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
<Field class="form-field form-field-toggle m-b-0" name="emailPassword.enabled" let:uniqueId>
|
<Field class="form-field form-field-toggle m-b-0" name="emailAuth.enabled" let:uniqueId>
|
||||||
<input type="checkbox" id={uniqueId} bind:checked={config.enabled} />
|
<input type="checkbox" id={uniqueId} bind:checked={config.enabled} />
|
||||||
<label for={uniqueId}>Enable</label>
|
<label for={uniqueId}>Enable</label>
|
||||||
</Field>
|
</Field>
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
{#if config.enabled}
|
{#if config.enabled}
|
||||||
<div class="grid" transition:slide|local={{ duration: 150 }}>
|
<div class="grid" transition:slide|local={{ duration: 150 }}>
|
||||||
<div class="col-sm-12 m-t-sm">
|
<div class="col-sm-12 m-t-sm">
|
||||||
<Field class="form-field required" name="emailPassword.minPasswordLength" let:uniqueId>
|
<Field class="form-field required" name="emailAuth.minPasswordLength" let:uniqueId>
|
||||||
<label for={uniqueId}>Minimum password length</label>
|
<label for={uniqueId}>Minimum password length</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field
|
<Field
|
||||||
class="form-field {!CommonHelper.isEmpty(config.onlyDomains) ? 'disabled' : ''}"
|
class="form-field {!CommonHelper.isEmpty(config.onlyDomains) ? 'disabled' : ''}"
|
||||||
name="emailPassword.exceptDomains"
|
name="emailAuth.exceptDomains"
|
||||||
let:uniqueId
|
let:uniqueId
|
||||||
>
|
>
|
||||||
<label for={uniqueId}>
|
<label for={uniqueId}>
|
||||||
|
@ -97,7 +97,7 @@
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field
|
<Field
|
||||||
class="form-field {!CommonHelper.isEmpty(config.exceptDomains) ? 'disabled' : ''}"
|
class="form-field {!CommonHelper.isEmpty(config.exceptDomains) ? 'disabled' : ''}"
|
||||||
name="emailPassword.onlyDomains"
|
name="emailAuth.onlyDomains"
|
||||||
let:uniqueId
|
let:uniqueId
|
||||||
>
|
>
|
||||||
<label for="{uniqueId}.config.onlyDomains">
|
<label for="{uniqueId}.config.onlyDomains">
|
||||||
|
|
|
@ -0,0 +1,121 @@
|
||||||
|
<script>
|
||||||
|
import { scale } from "svelte/transition";
|
||||||
|
import tooltip from "@/actions/tooltip";
|
||||||
|
import { errors, removeError } from "@/stores/errors";
|
||||||
|
import { addInfoToast } from "@/stores/toasts";
|
||||||
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
|
import Accordion from "@/components/base/Accordion.svelte";
|
||||||
|
import Field from "@/components/base/Field.svelte";
|
||||||
|
|
||||||
|
export let key;
|
||||||
|
export let title;
|
||||||
|
export let config = {};
|
||||||
|
|
||||||
|
let accordion;
|
||||||
|
|
||||||
|
$: hasErrors = !CommonHelper.isEmpty(CommonHelper.getNestedVal($errors, key));
|
||||||
|
|
||||||
|
$: if (!config.enabled) {
|
||||||
|
removeError(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function expand() {
|
||||||
|
accordion?.expand();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function collapse() {
|
||||||
|
accordion?.collapse();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function collapseSiblings() {
|
||||||
|
accordion?.collapseSiblings();
|
||||||
|
}
|
||||||
|
|
||||||
|
function copy(param) {
|
||||||
|
CommonHelper.copyToClipboard(param);
|
||||||
|
addInfoToast(`Copied ${param} to clipboard`, 2000);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Accordion bind:this={accordion} on:expand on:collapse on:toggle {...$$restProps}>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
|
<div class="inline-flex">
|
||||||
|
<i class="ri-draft-line" />
|
||||||
|
<span class="txt">{title}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex-fill" />
|
||||||
|
|
||||||
|
{#if hasErrors}
|
||||||
|
<i
|
||||||
|
class="ri-error-warning-fill txt-danger"
|
||||||
|
transition:scale={{ duration: 150, start: 0.7 }}
|
||||||
|
use:tooltip={{ text: "Has errors", position: "left" }}
|
||||||
|
/>
|
||||||
|
{/if}
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<Field class="form-field required" name="{key}.subject" let:uniqueId>
|
||||||
|
<label for={uniqueId}>Subject</label>
|
||||||
|
<input type="text" id={uniqueId} bind:value={config.subject} spellcheck="false" required />
|
||||||
|
<div class="help-block">
|
||||||
|
Available placeholder parameters:
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{APP_NAME}")}>
|
||||||
|
{"{APP_NAME}"}
|
||||||
|
</span>,
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{APP_URL}")}>
|
||||||
|
{"{APP_URL}"}
|
||||||
|
</span>.
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field class="form-field required" name="{key}.actionUrl" let:uniqueId>
|
||||||
|
<label for={uniqueId}>Action URL</label>
|
||||||
|
<input type="text" id={uniqueId} bind:value={config.actionUrl} spellcheck="false" required />
|
||||||
|
<div class="help-block">
|
||||||
|
Available placeholder parameters:
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{APP_NAME}")}>
|
||||||
|
{"{APP_NAME}"}
|
||||||
|
</span>,
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{APP_URL}")}>
|
||||||
|
{"{APP_URL}"}
|
||||||
|
</span>,
|
||||||
|
<span
|
||||||
|
class="label label-sm link-primary txt-mono"
|
||||||
|
title="Required parameter"
|
||||||
|
on:click={() => copy("{TOKEN}")}>{"{TOKEN}"}</span
|
||||||
|
>.
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
|
|
||||||
|
<Field class="form-field m-0 required" name="{key}.body" let:uniqueId>
|
||||||
|
<label for={uniqueId}>Body (HTML)</label>
|
||||||
|
<textarea
|
||||||
|
id={uniqueId}
|
||||||
|
bind:value={config.body}
|
||||||
|
class="txt-mono"
|
||||||
|
spellcheck="false"
|
||||||
|
rows="12"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<div class="help-block">
|
||||||
|
Available placeholder parameters:
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{APP_NAME}")}>
|
||||||
|
{"{APP_NAME}"}
|
||||||
|
</span>,
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{APP_URL}")}>
|
||||||
|
{"{APP_URL}"}
|
||||||
|
</span>,
|
||||||
|
<span class="label label-sm link-primary txt-mono" on:click={() => copy("{TOKEN}")}>
|
||||||
|
{"{TOKEN}"}
|
||||||
|
</span>,
|
||||||
|
<span
|
||||||
|
class="label label-sm link-primary txt-mono"
|
||||||
|
title="Required parameter"
|
||||||
|
on:click={() => copy("{ACTION_URL}")}
|
||||||
|
>
|
||||||
|
{"{ACTION_URL}"}
|
||||||
|
</span>.
|
||||||
|
</div>
|
||||||
|
</Field>
|
||||||
|
</Accordion>
|
|
@ -9,11 +9,14 @@
|
||||||
|
|
||||||
$pageTitle = "Application settings";
|
$pageTitle = "Application settings";
|
||||||
|
|
||||||
|
let originalFormSettings = {};
|
||||||
let formSettings = {};
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
let initialHash = "";
|
let initialHash = "";
|
||||||
|
|
||||||
|
$: initialHash = JSON.stringify(originalFormSettings);
|
||||||
|
|
||||||
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
@ -57,7 +60,11 @@
|
||||||
logs: settings?.logs || {},
|
logs: settings?.logs || {},
|
||||||
};
|
};
|
||||||
|
|
||||||
initialHash = JSON.stringify(formSettings);
|
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -103,6 +110,16 @@
|
||||||
|
|
||||||
<div class="col-lg-12 flex">
|
<div class="col-lg-12 flex">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
{#if hasChanges}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-secondary btn-hint"
|
||||||
|
disabled={isSaving}
|
||||||
|
on:click={() => reset()}
|
||||||
|
>
|
||||||
|
<span class="txt">Cancel</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
|
|
@ -12,12 +12,14 @@
|
||||||
$pageTitle = "Auth providers";
|
$pageTitle = "Auth providers";
|
||||||
|
|
||||||
let emailAuthAccordion;
|
let emailAuthAccordion;
|
||||||
let authSettings = {};
|
let originalFormSettings = {};
|
||||||
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
let initialHash = "";
|
|
||||||
|
|
||||||
$: hasChanges = initialHash != JSON.stringify(authSettings);
|
$: initialHash = JSON.stringify(originalFormSettings);
|
||||||
|
|
||||||
|
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
|
@ -42,7 +44,7 @@
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await ApiClient.settings.update(CommonHelper.filterRedactedProps(authSettings));
|
const result = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
||||||
initSettings(result);
|
initSettings(result);
|
||||||
setErrors({});
|
setErrors({});
|
||||||
emailAuthAccordion?.collapseSiblings();
|
emailAuthAccordion?.collapseSiblings();
|
||||||
|
@ -57,18 +59,23 @@
|
||||||
function initSettings(data) {
|
function initSettings(data) {
|
||||||
data = data || {};
|
data = data || {};
|
||||||
|
|
||||||
authSettings = {};
|
formSettings = {
|
||||||
authSettings.emailAuth = Object.assign({ enabled: true }, data.emailAuth);
|
emailAuth: Object.assign({ enabled: true }, data.emailAuth),
|
||||||
|
};
|
||||||
|
|
||||||
const providers = ["googleAuth", "facebookAuth", "githubAuth", "gitlabAuth"];
|
const providers = ["googleAuth", "facebookAuth", "githubAuth", "gitlabAuth"];
|
||||||
for (const provider of providers) {
|
for (const provider of providers) {
|
||||||
authSettings[provider] = Object.assign(
|
formSettings[provider] = Object.assign(
|
||||||
{ enabled: false, allowRegistrations: true },
|
{ enabled: false, allowRegistrations: true },
|
||||||
data[provider]
|
data[provider]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
initialHash = JSON.stringify(authSettings);
|
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -93,28 +100,28 @@
|
||||||
<EmailAuthAccordion
|
<EmailAuthAccordion
|
||||||
bind:this={emailAuthAccordion}
|
bind:this={emailAuthAccordion}
|
||||||
single
|
single
|
||||||
bind:config={authSettings.emailAuth}
|
bind:config={formSettings.emailAuth}
|
||||||
/>
|
/>
|
||||||
<AuthProviderAccordion
|
<AuthProviderAccordion
|
||||||
single
|
single
|
||||||
key="googleAuth"
|
key="googleAuth"
|
||||||
title="Google"
|
title="Google"
|
||||||
icon="ri-google-line"
|
icon="ri-google-line"
|
||||||
bind:config={authSettings.googleAuth}
|
bind:config={formSettings.googleAuth}
|
||||||
/>
|
/>
|
||||||
<AuthProviderAccordion
|
<AuthProviderAccordion
|
||||||
single
|
single
|
||||||
key="facebookAuth"
|
key="facebookAuth"
|
||||||
title="Facebook"
|
title="Facebook"
|
||||||
icon="ri-facebook-line"
|
icon="ri-facebook-line"
|
||||||
bind:config={authSettings.facebookAuth}
|
bind:config={formSettings.facebookAuth}
|
||||||
/>
|
/>
|
||||||
<AuthProviderAccordion
|
<AuthProviderAccordion
|
||||||
single
|
single
|
||||||
key="githubAuth"
|
key="githubAuth"
|
||||||
title="GitHub"
|
title="GitHub"
|
||||||
icon="ri-github-line"
|
icon="ri-github-line"
|
||||||
bind:config={authSettings.githubAuth}
|
bind:config={formSettings.githubAuth}
|
||||||
/>
|
/>
|
||||||
<AuthProviderAccordion
|
<AuthProviderAccordion
|
||||||
single
|
single
|
||||||
|
@ -122,12 +129,22 @@
|
||||||
title="GitLab"
|
title="GitLab"
|
||||||
icon="ri-gitlab-line"
|
icon="ri-gitlab-line"
|
||||||
showSelfHostedFields
|
showSelfHostedFields
|
||||||
bind:config={authSettings.gitlabAuth}
|
bind:config={formSettings.gitlabAuth}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex m-t-base">
|
<div class="flex m-t-base">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
{#if hasChanges}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-secondary btn-hint"
|
||||||
|
disabled={isSaving}
|
||||||
|
on:click={() => reset()}
|
||||||
|
>
|
||||||
|
<span class="txt">Cancel</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
|
|
@ -3,24 +3,29 @@
|
||||||
import ApiClient from "@/utils/ApiClient";
|
import ApiClient from "@/utils/ApiClient";
|
||||||
import CommonHelper from "@/utils/CommonHelper";
|
import CommonHelper from "@/utils/CommonHelper";
|
||||||
import { pageTitle } from "@/stores/app";
|
import { pageTitle } from "@/stores/app";
|
||||||
|
import { setErrors } from "@/stores/errors";
|
||||||
import { addSuccessToast } from "@/stores/toasts";
|
import { addSuccessToast } from "@/stores/toasts";
|
||||||
import PageWrapper from "@/components/base/PageWrapper.svelte";
|
import PageWrapper from "@/components/base/PageWrapper.svelte";
|
||||||
import Field from "@/components/base/Field.svelte";
|
import Field from "@/components/base/Field.svelte";
|
||||||
import ObjectSelect from "@/components/base/ObjectSelect.svelte";
|
import ObjectSelect from "@/components/base/ObjectSelect.svelte";
|
||||||
import RedactedPasswordInput from "@/components/base/RedactedPasswordInput.svelte";
|
import RedactedPasswordInput from "@/components/base/RedactedPasswordInput.svelte";
|
||||||
import SettingsSidebar from "@/components/settings/SettingsSidebar.svelte";
|
import SettingsSidebar from "@/components/settings/SettingsSidebar.svelte";
|
||||||
|
import EmailTemplateAccordion from "@/components/settings/EmailTemplateAccordion.svelte";
|
||||||
|
|
||||||
const tlsOptions = [
|
const tlsOptions = [
|
||||||
{ label: "Optional (StartTLS)", value: false },
|
{ label: "Auto (StartTLS)", value: false },
|
||||||
{ label: "Always", value: true },
|
{ label: "Always", value: true },
|
||||||
];
|
];
|
||||||
|
|
||||||
$pageTitle = "Mail settings";
|
$pageTitle = "Mail settings";
|
||||||
|
|
||||||
|
let firstAccordion;
|
||||||
|
let originalFormSettings = {};
|
||||||
let formSettings = {};
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
let initialHash = "";
|
|
||||||
|
$: initialHash = JSON.stringify(originalFormSettings);
|
||||||
|
|
||||||
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
||||||
|
|
||||||
|
@ -49,6 +54,8 @@
|
||||||
try {
|
try {
|
||||||
const settings = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
const settings = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
||||||
init(settings);
|
init(settings);
|
||||||
|
setErrors({});
|
||||||
|
firstAccordion?.collapseSiblings();
|
||||||
addSuccessToast("Successfully saved mail settings.");
|
addSuccessToast("Successfully saved mail settings.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ApiClient.errorResponseHandler(err);
|
ApiClient.errorResponseHandler(err);
|
||||||
|
@ -62,7 +69,12 @@
|
||||||
meta: settings?.meta || {},
|
meta: settings?.meta || {},
|
||||||
smtp: settings?.smtp || {},
|
smtp: settings?.smtp || {},
|
||||||
};
|
};
|
||||||
initialHash = JSON.stringify(formSettings);
|
|
||||||
|
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -85,7 +97,7 @@
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<div class="loader" />
|
<div class="loader" />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="grid">
|
<div class="grid m-b-base">
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field class="form-field required" name="meta.senderName" let:uniqueId>
|
<Field class="form-field required" name="meta.senderName" let:uniqueId>
|
||||||
<label for={uniqueId}>Sender name</label>
|
<label for={uniqueId}>Sender name</label>
|
||||||
|
@ -109,49 +121,30 @@
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Field class="form-field required" name="meta.userVerificationUrl" let:uniqueId>
|
<div class="accordions">
|
||||||
<label for={uniqueId}>User verification page url</label>
|
<EmailTemplateAccordion
|
||||||
<input
|
bind:this={firstAccordion}
|
||||||
type="text"
|
single
|
||||||
id={uniqueId}
|
key="meta.verificationTemplate"
|
||||||
required
|
title={'Default "Verification" email template'}
|
||||||
bind:value={formSettings.meta.userVerificationUrl}
|
bind:config={formSettings.meta.verificationTemplate}
|
||||||
/>
|
/>
|
||||||
<div class="help-block">
|
|
||||||
Used in the user verification email. Available placeholder parameters:
|
|
||||||
<code>%APP_URL%</code>, <code>%TOKEN%</code>.
|
|
||||||
</div>
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
<Field class="form-field required" name="meta.userResetPasswordUrl" let:uniqueId>
|
<EmailTemplateAccordion
|
||||||
<label for={uniqueId}>User reset password page url</label>
|
single
|
||||||
<input
|
key="meta.resetPasswordTemplate"
|
||||||
type="text"
|
title={'Default "Password reset" email template'}
|
||||||
id={uniqueId}
|
bind:config={formSettings.meta.resetPasswordTemplate}
|
||||||
required
|
/>
|
||||||
bind:value={formSettings.meta.userResetPasswordUrl}
|
|
||||||
/>
|
|
||||||
<div class="help-block">
|
|
||||||
Used in the user password reset email. Available placeholder parameters:
|
|
||||||
<code>%APP_URL%</code>, <code>%TOKEN%</code>.
|
|
||||||
</div>
|
|
||||||
</Field>
|
|
||||||
|
|
||||||
<Field class="form-field required" name="meta.userConfirmEmailChangeUrl" let:uniqueId>
|
<EmailTemplateAccordion
|
||||||
<label for={uniqueId}>User confirm email change page url</label>
|
single
|
||||||
<input
|
key="meta.confirmEmailChangeTemplate"
|
||||||
type="text"
|
title={'Default "Confirm email change" email template'}
|
||||||
id={uniqueId}
|
bind:config={formSettings.meta.confirmEmailChangeTemplate}
|
||||||
required
|
/>
|
||||||
bind:value={formSettings.meta.userConfirmEmailChangeUrl}
|
|
||||||
/>
|
|
||||||
<div class="help-block">
|
|
||||||
Used in the user email change confirmation email. Available placeholder
|
|
||||||
parameters:
|
|
||||||
<code>%APP_URL%</code>, <code>%TOKEN%</code>.
|
|
||||||
</div>
|
|
||||||
</Field>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
@ -228,6 +221,16 @@
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
{#if hasChanges}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-secondary btn-hint"
|
||||||
|
disabled={isSaving}
|
||||||
|
on:click={() => reset()}
|
||||||
|
>
|
||||||
|
<span class="txt">Cancel</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
|
|
@ -13,13 +13,14 @@
|
||||||
|
|
||||||
$pageTitle = "Files storage";
|
$pageTitle = "Files storage";
|
||||||
|
|
||||||
let s3 = {};
|
let originalFormSettings = {};
|
||||||
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
let initialHash = "";
|
|
||||||
let initialEnabled = false;
|
|
||||||
|
|
||||||
$: hasChanges = initialHash != JSON.stringify(s3);
|
$: initialHash = JSON.stringify(originalFormSettings);
|
||||||
|
|
||||||
|
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
|
@ -44,10 +45,10 @@
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const settings = await ApiClient.settings.update(CommonHelper.filterRedactedProps({ s3 }));
|
const settings = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
||||||
init(settings);
|
init(settings);
|
||||||
setErrors({});
|
setErrors({});
|
||||||
addSuccessToast("Successfully saved Files storage settings.");
|
addSuccessToast("Successfully saved files storage settings.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
ApiClient.errorResponseHandler(err);
|
ApiClient.errorResponseHandler(err);
|
||||||
}
|
}
|
||||||
|
@ -56,9 +57,14 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
function init(settings = {}) {
|
function init(settings = {}) {
|
||||||
s3 = settings?.s3 || {};
|
formSettings = {
|
||||||
initialEnabled = s3.enabled;
|
s3: settings?.s3 || {},
|
||||||
initialHash = JSON.stringify(s3);
|
};
|
||||||
|
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -85,11 +91,11 @@
|
||||||
<div class="loader" />
|
<div class="loader" />
|
||||||
{:else}
|
{:else}
|
||||||
<Field class="form-field form-field-toggle" let:uniqueId>
|
<Field class="form-field form-field-toggle" let:uniqueId>
|
||||||
<input type="checkbox" id={uniqueId} required bind:checked={s3.enabled} />
|
<input type="checkbox" id={uniqueId} required bind:checked={formSettings.s3.enabled} />
|
||||||
<label for={uniqueId}>Use S3 storage</label>
|
<label for={uniqueId}>Use S3 storage</label>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
{#if initialEnabled != s3.enabled}
|
{#if originalFormSettings.s3?.enabled != formSettings.s3.enabled}
|
||||||
<div transition:slide|local={{ duration: 150 }}>
|
<div transition:slide|local={{ duration: 150 }}>
|
||||||
<div class="alert alert-warning m-0">
|
<div class="alert alert-warning m-0">
|
||||||
<div class="icon">
|
<div class="icon">
|
||||||
|
@ -98,9 +104,12 @@
|
||||||
<div class="content">
|
<div class="content">
|
||||||
If you have existing uploaded files, you'll have to migrate them manually from
|
If you have existing uploaded files, you'll have to migrate them manually from
|
||||||
the
|
the
|
||||||
<strong>{initialEnabled ? "S3 storage" : "local file system"}</strong>
|
<strong>
|
||||||
|
{originalFormSettings.s3?.enabled ? "S3 storage" : "local file system"}
|
||||||
|
</strong>
|
||||||
to the
|
to the
|
||||||
<strong>{s3.enabled ? "S3 storage" : "local file system"}</strong>.
|
<strong>{formSettings.s3.enabled ? "S3 storage" : "local file system"}</strong
|
||||||
|
>.
|
||||||
<br />
|
<br />
|
||||||
There are numerous command line tools that can help you, such as:
|
There are numerous command line tools that can help you, such as:
|
||||||
<a
|
<a
|
||||||
|
@ -125,41 +134,69 @@
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
{#if s3.enabled}
|
{#if formSettings.s3.enabled}
|
||||||
<div class="grid" transition:slide|local={{ duration: 150 }}>
|
<div class="grid" transition:slide|local={{ duration: 150 }}>
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<Field class="form-field required" name="s3.endpoint" let:uniqueId>
|
<Field class="form-field required" name="s3.endpoint" let:uniqueId>
|
||||||
<label for={uniqueId}>Endpoint</label>
|
<label for={uniqueId}>Endpoint</label>
|
||||||
<input type="text" id={uniqueId} required bind:value={s3.endpoint} />
|
<input
|
||||||
|
type="text"
|
||||||
|
id={uniqueId}
|
||||||
|
required
|
||||||
|
bind:value={formSettings.s3.endpoint}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field class="form-field required" name="s3.bucket" let:uniqueId>
|
<Field class="form-field required" name="s3.bucket" let:uniqueId>
|
||||||
<label for={uniqueId}>Bucket</label>
|
<label for={uniqueId}>Bucket</label>
|
||||||
<input type="text" id={uniqueId} required bind:value={s3.bucket} />
|
<input
|
||||||
|
type="text"
|
||||||
|
id={uniqueId}
|
||||||
|
required
|
||||||
|
bind:value={formSettings.s3.bucket}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field class="form-field required" name="s3.region" let:uniqueId>
|
<Field class="form-field required" name="s3.region" let:uniqueId>
|
||||||
<label for={uniqueId}>Region</label>
|
<label for={uniqueId}>Region</label>
|
||||||
<input type="text" id={uniqueId} required bind:value={s3.region} />
|
<input
|
||||||
|
type="text"
|
||||||
|
id={uniqueId}
|
||||||
|
required
|
||||||
|
bind:value={formSettings.s3.region}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field class="form-field required" name="s3.accessKey" let:uniqueId>
|
<Field class="form-field required" name="s3.accessKey" let:uniqueId>
|
||||||
<label for={uniqueId}>Access key</label>
|
<label for={uniqueId}>Access key</label>
|
||||||
<input type="text" id={uniqueId} required bind:value={s3.accessKey} />
|
<input
|
||||||
|
type="text"
|
||||||
|
id={uniqueId}
|
||||||
|
required
|
||||||
|
bind:value={formSettings.s3.accessKey}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-6">
|
<div class="col-lg-6">
|
||||||
<Field class="form-field required" name="s3.secret" let:uniqueId>
|
<Field class="form-field required" name="s3.secret" let:uniqueId>
|
||||||
<label for={uniqueId}>Secret</label>
|
<label for={uniqueId}>Secret</label>
|
||||||
<RedactedPasswordInput id={uniqueId} required bind:value={s3.secret} />
|
<RedactedPasswordInput
|
||||||
|
id={uniqueId}
|
||||||
|
required
|
||||||
|
bind:value={formSettings.s3.secret}
|
||||||
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-lg-12">
|
<div class="col-lg-12">
|
||||||
<Field class="form-field" name="s3.forcePathStyle" let:uniqueId>
|
<Field class="form-field" name="s3.forcePathStyle" let:uniqueId>
|
||||||
<input type="checkbox" id={uniqueId} bind:checked={s3.forcePathStyle} />
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
id={uniqueId}
|
||||||
|
bind:checked={formSettings.s3.forcePathStyle}
|
||||||
|
/>
|
||||||
<label for={uniqueId}>
|
<label for={uniqueId}>
|
||||||
<span class="txt">Force path-style addressing</span>
|
<span class="txt">Force path-style addressing</span>
|
||||||
<i
|
<i
|
||||||
|
@ -179,6 +216,16 @@
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
{#if hasChanges}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-secondary btn-hint"
|
||||||
|
disabled={isSaving}
|
||||||
|
on:click={() => reset()}
|
||||||
|
>
|
||||||
|
<span class="txt">Cancel</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
|
|
@ -18,12 +18,14 @@
|
||||||
|
|
||||||
$pageTitle = "Token options";
|
$pageTitle = "Token options";
|
||||||
|
|
||||||
let tokenSettings = {};
|
let originalFormSettings = {};
|
||||||
|
let formSettings = {};
|
||||||
let isLoading = false;
|
let isLoading = false;
|
||||||
let isSaving = false;
|
let isSaving = false;
|
||||||
let initialHash = "";
|
|
||||||
|
|
||||||
$: hasChanges = initialHash != JSON.stringify(tokenSettings);
|
$: initialHash = JSON.stringify(originalFormSettings);
|
||||||
|
|
||||||
|
$: hasChanges = initialHash != JSON.stringify(formSettings);
|
||||||
|
|
||||||
loadSettings();
|
loadSettings();
|
||||||
|
|
||||||
|
@ -48,7 +50,7 @@
|
||||||
isSaving = true;
|
isSaving = true;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await ApiClient.settings.update(CommonHelper.filterRedactedProps(tokenSettings));
|
const result = await ApiClient.settings.update(CommonHelper.filterRedactedProps(formSettings));
|
||||||
initSettings(result);
|
initSettings(result);
|
||||||
addSuccessToast("Successfully saved tokens options.");
|
addSuccessToast("Successfully saved tokens options.");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -60,15 +62,19 @@
|
||||||
|
|
||||||
function initSettings(data) {
|
function initSettings(data) {
|
||||||
data = data || {};
|
data = data || {};
|
||||||
tokenSettings = {};
|
formSettings = {};
|
||||||
|
|
||||||
for (const listItem of tokensList) {
|
for (const listItem of tokensList) {
|
||||||
tokenSettings[listItem.key] = {
|
formSettings[listItem.key] = {
|
||||||
duration: data[listItem.key]?.duration || 0,
|
duration: data[listItem.key]?.duration || 0,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
initialHash = JSON.stringify(tokenSettings);
|
originalFormSettings = JSON.parse(JSON.stringify(formSettings));
|
||||||
|
}
|
||||||
|
|
||||||
|
function reset() {
|
||||||
|
formSettings = JSON.parse(JSON.stringify(originalFormSettings || {}));
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -98,19 +104,19 @@
|
||||||
type="number"
|
type="number"
|
||||||
id={uniqueId}
|
id={uniqueId}
|
||||||
required
|
required
|
||||||
bind:value={tokenSettings[token.key].duration}
|
bind:value={formSettings[token.key].duration}
|
||||||
/>
|
/>
|
||||||
<div class="help-block">
|
<div class="help-block">
|
||||||
<span
|
<span
|
||||||
class="link-primary"
|
class="link-primary"
|
||||||
class:txt-success={tokenSettings[token.key].secret}
|
class:txt-success={formSettings[token.key].secret}
|
||||||
on:click={() => {
|
on:click={() => {
|
||||||
// toggle
|
// toggle
|
||||||
if (tokenSettings[token.key].secret) {
|
if (formSettings[token.key].secret) {
|
||||||
delete tokenSettings[token.key].secret;
|
delete formSettings[token.key].secret;
|
||||||
tokenSettings[token.key] = tokenSettings[token.key];
|
formSettings[token.key] = formSettings[token.key];
|
||||||
} else {
|
} else {
|
||||||
tokenSettings[token.key].secret = CommonHelper.randomString(50);
|
formSettings[token.key].secret = CommonHelper.randomString(50);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -122,6 +128,16 @@
|
||||||
|
|
||||||
<div class="flex">
|
<div class="flex">
|
||||||
<div class="flex-fill" />
|
<div class="flex-fill" />
|
||||||
|
{#if hasChanges}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-secondary btn-hint"
|
||||||
|
disabled={isSaving}
|
||||||
|
on:click={() => reset()}
|
||||||
|
>
|
||||||
|
<span class="txt">Cancel</span>
|
||||||
|
</button>
|
||||||
|
{/if}
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="btn btn-expanded"
|
class="btn btn-expanded"
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
<div class="sidebar-title">
|
<div class="sidebar-title">
|
||||||
<span class="txt">Sync</span>
|
<span class="txt">Sync</span>
|
||||||
<small class="label label-danger label-compact">Experimental</small>
|
<small class="label label-danger label-sm">Experimental</small>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<a
|
||||||
href="/settings/export-collections"
|
href="/settings/export-collections"
|
||||||
|
|
|
@ -35,7 +35,7 @@
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<div class="icon"><i class="ri-checkbox-circle-line" /></div>
|
<div class="icon"><i class="ri-checkbox-circle-line" /></div>
|
||||||
<div class="content txt-bold">
|
<div class="content txt-bold">
|
||||||
<p>Email address changed</p>
|
<p>Successfully changed the user email address.</p>
|
||||||
<p>You can now sign in with your new email address.</p>
|
<p>You can now sign in with your new email address.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -36,7 +36,7 @@
|
||||||
<div class="alert alert-success">
|
<div class="alert alert-success">
|
||||||
<div class="icon"><i class="ri-checkbox-circle-line" /></div>
|
<div class="icon"><i class="ri-checkbox-circle-line" /></div>
|
||||||
<div class="content txt-bold">
|
<div class="content txt-bold">
|
||||||
<p>Password changed</p>
|
<p>Successfully changed the user password.</p>
|
||||||
<p>You can now sign in with your new password.</p>
|
<p>You can now sign in with your new password.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -443,7 +443,7 @@ a,
|
||||||
background: var(--baseAlt2Color);
|
background: var(--baseAlt2Color);
|
||||||
color: var(--txtPrimaryColor);
|
color: var(--txtPrimaryColor);
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
&.label-compact {
|
&.label-sm {
|
||||||
font-size: var(--xsFontSize);
|
font-size: var(--xsFontSize);
|
||||||
padding: 3px 5px;
|
padding: 3px 5px;
|
||||||
min-height: 18px;
|
min-height: 18px;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
--warningColor: #ff8e3c;
|
--warningColor: #ff8e3c;
|
||||||
--warningAltColor: #ffe7d6;
|
--warningAltColor: #ffe7d6;
|
||||||
|
|
||||||
--overlayColor: rgba(70, 85, 100, 0.3);
|
--overlayColor: rgba(70, 82, 110, 0.3);
|
||||||
--tooltipColor: rgba(0, 0, 0, 0.85);
|
--tooltipColor: rgba(0, 0, 0, 0.85);
|
||||||
--shadowColor: rgba(0, 0, 0, 0.05);
|
--shadowColor: rgba(0, 0, 0, 0.05);
|
||||||
|
|
||||||
|
|
|
@ -284,7 +284,7 @@ export default class CommonHelper {
|
||||||
*/
|
*/
|
||||||
static getNestedVal(data, path, defaultVal = null, delimiter = ".") {
|
static getNestedVal(data, path, defaultVal = null, delimiter = ".") {
|
||||||
let result = data || {};
|
let result = data || {};
|
||||||
let parts = path.split(delimiter);
|
let parts = (path || '').split(delimiter);
|
||||||
|
|
||||||
for (const part of parts) {
|
for (const part of parts) {
|
||||||
if (
|
if (
|
||||||
|
@ -353,7 +353,7 @@ export default class CommonHelper {
|
||||||
*/
|
*/
|
||||||
static deleteByPath(data, path, delimiter = ".") {
|
static deleteByPath(data, path, delimiter = ".") {
|
||||||
let result = data || {};
|
let result = data || {};
|
||||||
let parts = path.split(delimiter);
|
let parts = (path || '').split(delimiter);
|
||||||
let lastPart = parts.pop();
|
let lastPart = parts.pop();
|
||||||
|
|
||||||
for (const part of parts) {
|
for (const part of parts) {
|
||||||
|
|
Loading…
Reference in New Issue