mirror of
https://github.com/mjl-/mox.git
synced 2024-12-26 16:33:47 +03:00
use type config.Account in sherpa api for better typing, and update to latest sherpa lib
typescript now knows the full types, not just "any" for account config. inline structs previously in config.Account are given their own type definition so sherpa can generate types. also update to latest sherpa lib that knows about time.Duration, to be used soon.
This commit is contained in:
parent
b7d6540d51
commit
4012b72d96
16 changed files with 911 additions and 123 deletions
|
@ -356,28 +356,32 @@ type Route struct {
|
|||
|
||||
// todo: move RejectsMailbox to store.Mailbox.SpecialUse, possibly with "X" prefix?
|
||||
|
||||
type SubjectPass struct {
|
||||
Period time.Duration `sconf-doc:"How long unique values are accepted after generating, e.g. 12h."` // todo: have a reasonable default for this?
|
||||
}
|
||||
|
||||
type AutomaticJunkFlags struct {
|
||||
Enabled bool `sconf-doc:"If enabled, flags will be set automatically if they match a regular expression below. When two of the three mailbox regular expressions are set, the remaining one will match all unmatched messages. Messages are matched in the order specified and the search stops on the first match. Mailboxes are lowercased before matching."`
|
||||
JunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(junk|spam)."`
|
||||
NeutralMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(inbox|neutral|postmaster|dmarc|tlsrpt|rejects), and you may wish to add trash depending on how you use it, or leave this empty."`
|
||||
NotJunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: .* or an empty string."`
|
||||
}
|
||||
|
||||
type Account struct {
|
||||
Domain string `sconf-doc:"Default domain for account. Deprecated behaviour: If a destination is not a full address but only a localpart, this domain is added to form a full address."`
|
||||
Description string `sconf:"optional" sconf-doc:"Free form description, e.g. full name or alternative contact info."`
|
||||
FullName string `sconf:"optional" sconf-doc:"Full name, to use in message From header when composing messages in webmail. Can be overridden per destination."`
|
||||
Destinations map[string]Destination `sconf:"optional" sconf-doc:"Destinations, keys are email addresses (with IDNA domains). All destinations are allowed for logging in with IMAP/SMTP/webmail. If no destinations are configured, the account can not login. If the address is of the form '@domain', i.e. with localpart missing, it serves as a catchall for the domain, matching all messages that are not explicitly configured. Deprecated behaviour: If the address is not a full address but a localpart, it is combined with Domain to form a full address."`
|
||||
SubjectPass struct {
|
||||
Period time.Duration `sconf-doc:"How long unique values are accepted after generating, e.g. 12h."` // todo: have a reasonable default for this?
|
||||
} `sconf:"optional" sconf-doc:"If configured, messages classified as weakly spam are rejected with instructions to retry delivery, but this time with a signed token added to the subject. During the next delivery attempt, the signed token will bypass the spam filter. Messages with a clear spam signal, such as a known bad reputation, are rejected/delayed without a signed token."`
|
||||
QuotaMessageSize int64 `sconf:"optional" sconf-doc:"Default maximum total message size in bytes for the account, overriding any globally configured default maximum size if non-zero. A negative value can be used to have no limit in case there is a limit by default. Attempting to add new messages to an account beyond its maximum total size will result in an error. Useful to prevent a single account from filling storage."`
|
||||
RejectsMailbox string `sconf:"optional" sconf-doc:"Mail that looks like spam will be rejected, but a copy can be stored temporarily in a mailbox, e.g. Rejects. If mail isn't coming in when you expect, you can look there. The mail still isn't accepted, so the remote mail server may retry (hopefully, if legitimate), or give up (hopefully, if indeed a spammer). Messages are automatically removed from this mailbox, so do not set it to a mailbox that has messages you want to keep."`
|
||||
KeepRejects bool `sconf:"optional" sconf-doc:"Don't automatically delete mail in the RejectsMailbox listed above. This can be useful, e.g. for future spam training."`
|
||||
AutomaticJunkFlags struct {
|
||||
Enabled bool `sconf-doc:"If enabled, flags will be set automatically if they match a regular expression below. When two of the three mailbox regular expressions are set, the remaining one will match all unmatched messages. Messages are matched in the order specified and the search stops on the first match. Mailboxes are lowercased before matching."`
|
||||
JunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(junk|spam)."`
|
||||
NeutralMailboxRegexp string `sconf:"optional" sconf-doc:"Example: ^(inbox|neutral|postmaster|dmarc|tlsrpt|rejects), and you may wish to add trash depending on how you use it, or leave this empty."`
|
||||
NotJunkMailboxRegexp string `sconf:"optional" sconf-doc:"Example: .* or an empty string."`
|
||||
} `sconf:"optional" sconf-doc:"Automatically set $Junk and $NotJunk flags based on mailbox messages are delivered/moved/copied to. Email clients typically have too limited functionality to conveniently set these flags, especially $NonJunk, but they can all move messages to a different mailbox, so this helps them."`
|
||||
JunkFilter *JunkFilter `sconf:"optional" sconf-doc:"Content-based filtering, using the junk-status of individual messages to rank words in such messages as spam or ham. It is recommended you always set the applicable (non)-junk status on messages, and that you do not empty your Trash because those messages contain valuable ham/spam training information."` // todo: sane defaults for junkfilter
|
||||
MaxOutgoingMessagesPerDay int `sconf:"optional" sconf-doc:"Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000."`
|
||||
MaxFirstTimeRecipientsPerDay int `sconf:"optional" sconf-doc:"Maximum number of first-time recipients in outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 200."`
|
||||
NoFirstTimeSenderDelay bool `sconf:"optional" sconf-doc:"Do not apply a delay to SMTP connections before accepting an incoming message from a first-time sender. Can be useful for accounts that sends automated responses and want instant replies."`
|
||||
Routes []Route `sconf:"optional" sconf-doc:"Routes for delivering outgoing messages through the queue. Each delivery attempt evaluates these account routes, domain routes and finally global routes. The transport of the first matching route is used in the delivery attempt. If no routes match, which is the default with no configured routes, messages are delivered directly from the queue."`
|
||||
Domain string `sconf-doc:"Default domain for account. Deprecated behaviour: If a destination is not a full address but only a localpart, this domain is added to form a full address."`
|
||||
Description string `sconf:"optional" sconf-doc:"Free form description, e.g. full name or alternative contact info."`
|
||||
FullName string `sconf:"optional" sconf-doc:"Full name, to use in message From header when composing messages in webmail. Can be overridden per destination."`
|
||||
Destinations map[string]Destination `sconf:"optional" sconf-doc:"Destinations, keys are email addresses (with IDNA domains). All destinations are allowed for logging in with IMAP/SMTP/webmail. If no destinations are configured, the account can not login. If the address is of the form '@domain', i.e. with localpart missing, it serves as a catchall for the domain, matching all messages that are not explicitly configured. Deprecated behaviour: If the address is not a full address but a localpart, it is combined with Domain to form a full address."`
|
||||
SubjectPass SubjectPass `sconf:"optional" sconf-doc:"If configured, messages classified as weakly spam are rejected with instructions to retry delivery, but this time with a signed token added to the subject. During the next delivery attempt, the signed token will bypass the spam filter. Messages with a clear spam signal, such as a known bad reputation, are rejected/delayed without a signed token."`
|
||||
QuotaMessageSize int64 `sconf:"optional" sconf-doc:"Default maximum total message size in bytes for the account, overriding any globally configured default maximum size if non-zero. A negative value can be used to have no limit in case there is a limit by default. Attempting to add new messages to an account beyond its maximum total size will result in an error. Useful to prevent a single account from filling storage."`
|
||||
RejectsMailbox string `sconf:"optional" sconf-doc:"Mail that looks like spam will be rejected, but a copy can be stored temporarily in a mailbox, e.g. Rejects. If mail isn't coming in when you expect, you can look there. The mail still isn't accepted, so the remote mail server may retry (hopefully, if legitimate), or give up (hopefully, if indeed a spammer). Messages are automatically removed from this mailbox, so do not set it to a mailbox that has messages you want to keep."`
|
||||
KeepRejects bool `sconf:"optional" sconf-doc:"Don't automatically delete mail in the RejectsMailbox listed above. This can be useful, e.g. for future spam training."`
|
||||
AutomaticJunkFlags AutomaticJunkFlags `sconf:"optional" sconf-doc:"Automatically set $Junk and $NotJunk flags based on mailbox messages are delivered/moved/copied to. Email clients typically have too limited functionality to conveniently set these flags, especially $NonJunk, but they can all move messages to a different mailbox, so this helps them."`
|
||||
JunkFilter *JunkFilter `sconf:"optional" sconf-doc:"Content-based filtering, using the junk-status of individual messages to rank words in such messages as spam or ham. It is recommended you always set the applicable (non)-junk status on messages, and that you do not empty your Trash because those messages contain valuable ham/spam training information."` // todo: sane defaults for junkfilter
|
||||
MaxOutgoingMessagesPerDay int `sconf:"optional" sconf-doc:"Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000."`
|
||||
MaxFirstTimeRecipientsPerDay int `sconf:"optional" sconf-doc:"Maximum number of first-time recipients in outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 200."`
|
||||
NoFirstTimeSenderDelay bool `sconf:"optional" sconf-doc:"Do not apply a delay to SMTP connections before accepting an incoming message from a first-time sender. Can be useful for accounts that sends automated responses and want instant replies."`
|
||||
Routes []Route `sconf:"optional" sconf-doc:"Routes for delivering outgoing messages through the queue. Each delivery attempt evaluates these account routes, domain routes and finally global routes. The transport of the first matching route is used in the delivery attempt. If no routes match, which is the default with no configured routes, messages are delivered directly from the queue."`
|
||||
|
||||
DNSDomain dns.Domain `sconf:"-"` // Parsed form of Domain.
|
||||
JunkMailbox *regexp.Regexp `sconf:"-" json:"-"`
|
||||
|
|
2
go.mod
2
go.mod
|
@ -8,7 +8,7 @@ require (
|
|||
github.com/mjl-/bstore v0.0.5
|
||||
github.com/mjl-/sconf v0.0.6
|
||||
github.com/mjl-/sherpa v0.6.7
|
||||
github.com/mjl-/sherpadoc v0.0.12
|
||||
github.com/mjl-/sherpadoc v0.0.13
|
||||
github.com/mjl-/sherpaprom v0.0.2
|
||||
github.com/mjl-/sherpats v0.0.6
|
||||
github.com/prometheus/client_golang v1.18.0
|
||||
|
|
4
go.sum
4
go.sum
|
@ -35,8 +35,8 @@ github.com/mjl-/sconf v0.0.6/go.mod h1:uF8OdWtLT8La3i4ln176i1pB0ps9pXGCaABEU55Zk
|
|||
github.com/mjl-/sherpa v0.6.7 h1:C5F8XQdV5nCuS4fvB+ye/ziUQrajEhOoj/t2w5T14BY=
|
||||
github.com/mjl-/sherpa v0.6.7/go.mod h1:dSpAOdgpwdqQZ72O4n3EHo/tR68eKyan8tYYraUMPNc=
|
||||
github.com/mjl-/sherpadoc v0.0.0-20190505200843-c0a7f43f5f1d/go.mod h1:5khTKxoKKNXcB8bkVUO6GlzC7PFtMmkHq578lPbmnok=
|
||||
github.com/mjl-/sherpadoc v0.0.12 h1:6hVe2Z0DnwjC0bfuOwfz8ov7JTCUU49cEaj7h22NiPk=
|
||||
github.com/mjl-/sherpadoc v0.0.12/go.mod h1:vh5zcsk3j/Tvm725EY+unTZb3EZcZcpiEQzrODSa6+I=
|
||||
github.com/mjl-/sherpadoc v0.0.13 h1:Rem75lUlFsgX6TPTdtBxskY/Ze/yivaRkFw1H1MUmFw=
|
||||
github.com/mjl-/sherpadoc v0.0.13/go.mod h1:vh5zcsk3j/Tvm725EY+unTZb3EZcZcpiEQzrODSa6+I=
|
||||
github.com/mjl-/sherpaprom v0.0.2 h1:1dlbkScsNafM5jURI44uiWrZMSwfZtcOFEEq7vx2C1Y=
|
||||
github.com/mjl-/sherpaprom v0.0.2/go.mod h1:cl5nMNOvqhzMiQJ2FzccQ9ReivjHXe53JhOVkPfSvw4=
|
||||
github.com/mjl-/sherpats v0.0.6 h1:2lSoJbb+jkjLOdlvoMxItq0QQrrnkH+rnm3PMRfpbmA=
|
||||
|
|
9
vendor/github.com/mjl-/sherpadoc/cmd/sherpadoc/parse.go
generated
vendored
9
vendor/github.com/mjl-/sherpadoc/cmd/sherpadoc/parse.go
generated
vendored
|
@ -538,6 +538,8 @@ func parseSelector(t *ast.SelectorExpr, srcTypeName string, sec *section, pp *pa
|
|||
|
||||
if pkgName == "time" && typeName == "Time" {
|
||||
return "timestamp"
|
||||
} else if pkgName == "time" && typeName == "Duration" {
|
||||
return "int64"
|
||||
}
|
||||
if pkgName == "sherpa" {
|
||||
switch typeName {
|
||||
|
@ -746,8 +748,8 @@ func (pp *parsedPackage) ensurePackageParsed(importPath string) *parsedPackage {
|
|||
return npp
|
||||
}
|
||||
|
||||
// LookupPackageImportPath returns the import/package path for pkgName as used as
|
||||
// used in the type named typeName.
|
||||
// LookupPackageImportPath returns the import/package path for pkgName as used
|
||||
// in the type named typeName.
|
||||
func (pp *parsedPackage) lookupPackageImportPath(typeName, pkgName string) string {
|
||||
file := pp.lookupTypeFile(typeName)
|
||||
for _, imp := range file.Imports {
|
||||
|
@ -758,7 +760,8 @@ func (pp *parsedPackage) lookupPackageImportPath(typeName, pkgName string) strin
|
|||
return ""
|
||||
}
|
||||
|
||||
// LookupTypeFile returns the go source file that containst he definition of the type named typeName.
|
||||
// LookupTypeFile returns the go source file that contains the definition of
|
||||
// the type named typeName.
|
||||
func (pp *parsedPackage) lookupTypeFile(typeName string) *ast.File {
|
||||
for _, file := range pp.Pkg.Files {
|
||||
for _, decl := range file.Decls {
|
||||
|
|
2
vendor/modules.txt
vendored
2
vendor/modules.txt
vendored
|
@ -25,7 +25,7 @@ github.com/mjl-/sconf
|
|||
# github.com/mjl-/sherpa v0.6.7
|
||||
## explicit; go 1.12
|
||||
github.com/mjl-/sherpa
|
||||
# github.com/mjl-/sherpadoc v0.0.12
|
||||
# github.com/mjl-/sherpadoc v0.0.13
|
||||
## explicit; go 1.16
|
||||
github.com/mjl-/sherpadoc
|
||||
github.com/mjl-/sherpadoc/cmd/sherpadoc
|
||||
|
|
|
@ -27,7 +27,6 @@ import (
|
|||
"github.com/mjl-/sherpaprom"
|
||||
|
||||
"github.com/mjl-/mox/config"
|
||||
"github.com/mjl-/mox/dns"
|
||||
"github.com/mjl-/mox/mlog"
|
||||
"github.com/mjl-/mox/mox-"
|
||||
"github.com/mjl-/mox/moxvar"
|
||||
|
@ -412,13 +411,10 @@ func (Account) SetPassword(ctx context.Context, password string) {
|
|||
xcheckf(ctx, err, "restoring session after password reset")
|
||||
}
|
||||
|
||||
// Account returns information about the account: full name, the default domain,
|
||||
// and the destinations (keys are email addresses, or localparts to the default
|
||||
// domain). todo: replace with a function that returns the whole account, when
|
||||
// sherpadoc understands unnamed struct fields.
|
||||
// Account returns information about the account.
|
||||
// StorageUsed is the sum of the sizes of all messages, in bytes.
|
||||
// StorageLimit is the maximum storage that can be used, or 0 if there is no limit.
|
||||
func (Account) Account(ctx context.Context) (fullName string, defaultDomain dns.Domain, destinations map[string]config.Destination, storageUsed, storageLimit int64) {
|
||||
func (Account) Account(ctx context.Context) (account config.Account, storageUsed, storageLimit int64) {
|
||||
log := pkglog.WithContext(ctx)
|
||||
reqInfo := ctx.Value(requestInfoCtxKey).(requestInfo)
|
||||
|
||||
|
@ -443,7 +439,7 @@ func (Account) Account(ctx context.Context) (fullName string, defaultDomain dns.
|
|||
xcheckf(ctx, err, "get disk usage")
|
||||
})
|
||||
|
||||
return accConf.FullName, accConf.DNSDomain, accConf.Destinations, storageUsed, storageLimit
|
||||
return accConf, storageUsed, storageLimit
|
||||
}
|
||||
|
||||
func (Account) AccountSaveFullName(ctx context.Context, fullName string) {
|
||||
|
|
|
@ -228,20 +228,30 @@ const [dom, style, attr, prop] = (function () {
|
|||
// NOTE: GENERATED by github.com/mjl-/sherpats, DO NOT MODIFY
|
||||
var api;
|
||||
(function (api) {
|
||||
api.structTypes = { "Destination": true, "Domain": true, "ImportProgress": true, "Ruleset": true };
|
||||
api.structTypes = { "Account": true, "AutomaticJunkFlags": true, "Destination": true, "Domain": true, "ImportProgress": true, "JunkFilter": true, "Route": true, "Ruleset": true, "SubjectPass": true };
|
||||
api.stringsTypes = { "CSRFToken": true };
|
||||
api.intsTypes = {};
|
||||
api.types = {
|
||||
"Domain": { "Name": "Domain", "Docs": "", "Fields": [{ "Name": "ASCII", "Docs": "", "Typewords": ["string"] }, { "Name": "Unicode", "Docs": "", "Typewords": ["string"] }] },
|
||||
"Account": { "Name": "Account", "Docs": "", "Fields": [{ "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Description", "Docs": "", "Typewords": ["string"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }, { "Name": "Destinations", "Docs": "", "Typewords": ["{}", "Destination"] }, { "Name": "SubjectPass", "Docs": "", "Typewords": ["SubjectPass"] }, { "Name": "QuotaMessageSize", "Docs": "", "Typewords": ["int64"] }, { "Name": "RejectsMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "KeepRejects", "Docs": "", "Typewords": ["bool"] }, { "Name": "AutomaticJunkFlags", "Docs": "", "Typewords": ["AutomaticJunkFlags"] }, { "Name": "JunkFilter", "Docs": "", "Typewords": ["nullable", "JunkFilter"] }, { "Name": "MaxOutgoingMessagesPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "MaxFirstTimeRecipientsPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "NoFirstTimeSenderDelay", "Docs": "", "Typewords": ["bool"] }, { "Name": "Routes", "Docs": "", "Typewords": ["[]", "Route"] }, { "Name": "DNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"Destination": { "Name": "Destination", "Docs": "", "Fields": [{ "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Rulesets", "Docs": "", "Typewords": ["[]", "Ruleset"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }] },
|
||||
"Ruleset": { "Name": "Ruleset", "Docs": "", "Fields": [{ "Name": "SMTPMailFromRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "VerifiedDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "HeadersRegexp", "Docs": "", "Typewords": ["{}", "string"] }, { "Name": "IsForward", "Docs": "", "Typewords": ["bool"] }, { "Name": "ListAllowDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "AcceptRejectsToMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "VerifiedDNSDomain", "Docs": "", "Typewords": ["Domain"] }, { "Name": "ListAllowDNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"Domain": { "Name": "Domain", "Docs": "", "Fields": [{ "Name": "ASCII", "Docs": "", "Typewords": ["string"] }, { "Name": "Unicode", "Docs": "", "Typewords": ["string"] }] },
|
||||
"SubjectPass": { "Name": "SubjectPass", "Docs": "", "Fields": [{ "Name": "Period", "Docs": "", "Typewords": ["int64"] }] },
|
||||
"AutomaticJunkFlags": { "Name": "AutomaticJunkFlags", "Docs": "", "Fields": [{ "Name": "Enabled", "Docs": "", "Typewords": ["bool"] }, { "Name": "JunkMailboxRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "NeutralMailboxRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "NotJunkMailboxRegexp", "Docs": "", "Typewords": ["string"] }] },
|
||||
"JunkFilter": { "Name": "JunkFilter", "Docs": "", "Fields": [{ "Name": "Threshold", "Docs": "", "Typewords": ["float64"] }, { "Name": "Onegrams", "Docs": "", "Typewords": ["bool"] }, { "Name": "Twograms", "Docs": "", "Typewords": ["bool"] }, { "Name": "Threegrams", "Docs": "", "Typewords": ["bool"] }, { "Name": "MaxPower", "Docs": "", "Typewords": ["float64"] }, { "Name": "TopWords", "Docs": "", "Typewords": ["int32"] }, { "Name": "IgnoreWords", "Docs": "", "Typewords": ["float64"] }, { "Name": "RareWords", "Docs": "", "Typewords": ["int32"] }] },
|
||||
"Route": { "Name": "Route", "Docs": "", "Fields": [{ "Name": "FromDomain", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "ToDomain", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "MinimumAttempts", "Docs": "", "Typewords": ["int32"] }, { "Name": "Transport", "Docs": "", "Typewords": ["string"] }, { "Name": "FromDomainASCII", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "ToDomainASCII", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"ImportProgress": { "Name": "ImportProgress", "Docs": "", "Fields": [{ "Name": "Token", "Docs": "", "Typewords": ["string"] }] },
|
||||
"CSRFToken": { "Name": "CSRFToken", "Docs": "", "Values": null },
|
||||
};
|
||||
api.parser = {
|
||||
Domain: (v) => api.parse("Domain", v),
|
||||
Account: (v) => api.parse("Account", v),
|
||||
Destination: (v) => api.parse("Destination", v),
|
||||
Ruleset: (v) => api.parse("Ruleset", v),
|
||||
Domain: (v) => api.parse("Domain", v),
|
||||
SubjectPass: (v) => api.parse("SubjectPass", v),
|
||||
AutomaticJunkFlags: (v) => api.parse("AutomaticJunkFlags", v),
|
||||
JunkFilter: (v) => api.parse("JunkFilter", v),
|
||||
Route: (v) => api.parse("Route", v),
|
||||
ImportProgress: (v) => api.parse("ImportProgress", v),
|
||||
CSRFToken: (v) => api.parse("CSRFToken", v),
|
||||
};
|
||||
|
@ -306,16 +316,13 @@ var api;
|
|||
const params = [password];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
// Account returns information about the account: full name, the default domain,
|
||||
// and the destinations (keys are email addresses, or localparts to the default
|
||||
// domain). todo: replace with a function that returns the whole account, when
|
||||
// sherpadoc understands unnamed struct fields.
|
||||
// Account returns information about the account.
|
||||
// StorageUsed is the sum of the sizes of all messages, in bytes.
|
||||
// StorageLimit is the maximum storage that can be used, or 0 if there is no limit.
|
||||
async Account() {
|
||||
const fn = "Account";
|
||||
const paramTypes = [];
|
||||
const returnTypes = [["string"], ["Domain"], ["{}", "Destination"], ["int64"], ["int64"]];
|
||||
const returnTypes = [["Account"], ["int64"], ["int64"]];
|
||||
const params = [];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
|
@ -854,7 +861,7 @@ const formatQuotaSize = (v) => {
|
|||
return '' + v;
|
||||
};
|
||||
const index = async () => {
|
||||
const [accountFullName, domain, destinations, storageUsed, storageLimit] = await client.Account();
|
||||
const [acc, storageUsed, storageLimit] = await client.Account();
|
||||
let fullNameForm;
|
||||
let fullNameFieldset;
|
||||
let fullName;
|
||||
|
@ -945,12 +952,12 @@ const index = async () => {
|
|||
const exportForm = (filename) => {
|
||||
return dom.form(attr.target('_blank'), attr.method('POST'), attr.action('export/' + filename), dom.input(attr.type('hidden'), attr.name('csrf'), attr.value(localStorageGet('webaccountcsrftoken') || '')), dom.submitbutton('Export'));
|
||||
};
|
||||
dom._kids(page, crumbs('Mox Account'), dom.p('NOTE: Not all account settings can be configured through these pages yet. See the configuration file for more options.'), dom.div('Default domain: ', domain.ASCII ? domainString(domain) : '(none)'), dom.br(), fullNameForm = dom.form(fullNameFieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), 'Full name', dom.br(), fullName = dom.input(attr.value(accountFullName), attr.title('Name to use in From header when composing messages. Can be overridden per configured address.'))), ' ', dom.submitbutton('Save')), async function submit(e) {
|
||||
dom._kids(page, crumbs('Mox Account'), dom.p('NOTE: Not all account settings can be configured through these pages yet. See the configuration file for more options.'), dom.div('Default domain: ', acc.DNSDomain.ASCII ? domainString(acc.DNSDomain) : '(none)'), dom.br(), fullNameForm = dom.form(fullNameFieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), 'Full name', dom.br(), fullName = dom.input(attr.value(acc.FullName), attr.title('Name to use in From header when composing messages. Can be overridden per configured address.'))), ' ', dom.submitbutton('Save')), async function submit(e) {
|
||||
e.preventDefault();
|
||||
await check(fullNameFieldset, client.AccountSaveFullName(fullName.value));
|
||||
fullName.setAttribute('value', fullName.value);
|
||||
fullNameForm.reset();
|
||||
}), dom.br(), dom.h2('Addresses'), dom.ul(Object.entries(destinations || {}).length === 0 ? dom.li('(None, login disabled)') : [], Object.entries(destinations || {}).sort().map(t => dom.li(dom.a(t[0], attr.href('#destinations/' + t[0])), t[0].startsWith('@') ? ' (catchall)' : []))), dom.br(), dom.h2('Change password'), passwordForm = dom.form(passwordFieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), 'New password', dom.br(), password1 = dom.input(attr.type('password'), attr.autocomplete('new-password'), attr.required(''), function focus() {
|
||||
}), dom.br(), dom.h2('Addresses'), dom.ul(Object.entries(acc.Destinations || {}).length === 0 ? dom.li('(None, login disabled)') : [], Object.entries(acc.Destinations || {}).sort().map(t => dom.li(dom.a(t[0], attr.href('#destinations/' + t[0])), t[0].startsWith('@') ? ' (catchall)' : []))), dom.br(), dom.h2('Change password'), passwordForm = dom.form(passwordFieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), 'New password', dom.br(), password1 = dom.input(attr.type('password'), attr.autocomplete('new-password'), attr.required(''), function focus() {
|
||||
passwordHint.style.display = '';
|
||||
})), ' ', dom.label(style({ display: 'inline-block' }), 'New password repeat', dom.br(), password2 = dom.input(attr.type('password'), attr.autocomplete('new-password'), attr.required(''))), ' ', dom.submitbutton('Change password')), passwordHint = dom.div(style({ display: 'none', marginTop: '.5ex' }), dom.clickbutton('Generate random password', function click(e) {
|
||||
e.preventDefault();
|
||||
|
@ -1077,8 +1084,8 @@ const index = async () => {
|
|||
});
|
||||
};
|
||||
const destination = async (name) => {
|
||||
const [_, domain, destinations] = await client.Account();
|
||||
let dest = destinations[name];
|
||||
const [acc] = await client.Account();
|
||||
let dest = (acc.Destinations || {})[name];
|
||||
if (!dest) {
|
||||
throw new Error('destination not found');
|
||||
}
|
||||
|
@ -1145,7 +1152,7 @@ const destination = async (name) => {
|
|||
let defaultMailbox;
|
||||
let fullName;
|
||||
let saveButton;
|
||||
const addresses = [name, ...Object.keys(destinations || {}).filter(a => !a.startsWith('@') && a !== name)];
|
||||
const addresses = [name, ...Object.keys(acc.Destinations || {}).filter(a => !a.startsWith('@') && a !== name)];
|
||||
dom._kids(page, crumbs(crumblink('Mox Account', '#'), 'Destination ' + name), dom.div(dom.span('Default mailbox', attr.title('Default mailbox where email for this recipient is delivered to if it does not match any ruleset. Default is Inbox.')), dom.br(), defaultMailbox = dom.input(attr.value(dest.Mailbox), attr.placeholder('Inbox'))), dom.br(), dom.div(dom.span('Full name', attr.title('Name to use in From header when composing messages. If not set, the account default full name is used.')), dom.br(), fullName = dom.input(attr.value(dest.FullName))), dom.br(), dom.h2('Rulesets'), dom.p('Incoming messages are checked against the rulesets. If a ruleset matches, the message is delivered to the mailbox configured for the ruleset instead of to the default mailbox.'), dom.p('"Is Forward" does not affect matching, but changes prevents the sending mail server from being included in future junk classifications by clearing fields related to the forwarding email server (IP address, EHLO domain, MAIL FROM domain and a matching DKIM domain), and prevents DMARC rejects for forwarded messages.'), dom.p('"List allow domain" does not affect matching, but skips the regular spam checks if one of the verified domains is a (sub)domain of the domain mentioned here.'), dom.p('"Accept rejects to mailbox" does not affect matching, but causes messages classified as junk to be accepted and delivered to this mailbox, instead of being rejected during the SMTP transaction. Useful for incoming forwarded messages where rejecting incoming messages may cause the forwarding server to stop forwarding.'), dom.table(dom.thead(dom.tr(dom.th('SMTP "MAIL FROM" regexp', attr.title('Matches if this regular expression matches (a substring of) the SMTP MAIL FROM address (not the message From-header). E.g. user@example.org.')), dom.th('Verified domain', attr.title('Matches if this domain matches an SPF- and/or DKIM-verified (sub)domain.')), dom.th('Headers regexp', attr.title('Matches if these header field/value regular expressions all match (substrings of) the message headers. Header fields and valuees are converted to lower case before matching. Whitespace is trimmed from the value before matching. A header field can occur multiple times in a message, only one instance has to match. For mailing lists, you could match on ^list-id$ with the value typically the mailing list address in angled brackets with @ replaced with a dot, e.g. <name\\.lists\\.example\\.org>.')), dom.th('Is Forward', attr.title("Influences spam filtering only, this option does not change whether a message matches this ruleset. Can only be used together with SMTPMailFromRegexp and VerifiedDomain. SMTPMailFromRegexp must be set to the address used to deliver the forwarded message, e.g. '^user(|\\+.*)@forward\\.example$'. Changes to junk analysis: 1. Messages are not rejected for failing a DMARC policy, because a legitimate forwarded message without valid/intact/aligned DKIM signature would be rejected because any verified SPF domain will be 'unaligned', of the forwarding mail server. 2. The sending mail server IP address, and sending EHLO and MAIL FROM domains and matching DKIM domain aren't used in future reputation-based spam classifications (but other verified DKIM domains are) because the forwarding server is not a useful spam signal for future messages.")), dom.th('List allow domain', attr.title("Influences spam filtering only, this option does not change whether a message matches this ruleset. If this domain matches an SPF- and/or DKIM-verified (sub)domain, the message is accepted without further spam checks, such as a junk filter or DMARC reject evaluation. DMARC rejects should not apply for mailing lists that are not configured to rewrite the From-header of messages that don't have a passing DKIM signature of the From-domain. Otherwise, by rejecting messages, you may be automatically unsubscribed from the mailing list. The assumption is that mailing lists do their own spam filtering/moderation.")), dom.th('Allow rejects to mailbox', attr.title("Influences spam filtering only, this option does not change whether a message matches this ruleset. If a message is classified as spam, it isn't rejected during the SMTP transaction (the normal behaviour), but accepted during the SMTP transaction and delivered to the specified mailbox. The specified mailbox is not automatically cleaned up like the account global Rejects mailbox, unless set to that Rejects mailbox.")), dom.th('Mailbox', attr.title('Mailbox to deliver to if this ruleset matches.')), dom.th('Action'))), rulesetsTbody, dom.tfoot(dom.tr(dom.td(attr.colspan('7')), dom.td(dom.clickbutton('Add ruleset', function click() {
|
||||
addRulesetsRow({
|
||||
SMTPMailFromRegexp: '',
|
||||
|
@ -1178,7 +1185,7 @@ const destination = async (name) => {
|
|||
};
|
||||
await check(saveButton, client.DestinationSave(name, dest, newDest));
|
||||
window.location.reload(); // todo: only refresh part of ui
|
||||
}), dom.br(), dom.br(), dom.br(), dom.p("Apple's mail applications don't do account autoconfiguration, and when adding an account it can choose defaults that don't work with modern email servers. Adding an account through a \"mobileconfig\" profile file can be more convenient: It contains the IMAP/SMTP settings such as host name, port, TLS, authentication mechanism and user name. This profile does not contain a login password. Opening the profile adds it under Profiles in System Preferences (macOS) or Settings (iOS), where you can install it. These profiles are not signed, so users will have to ignore the warnings about them being unsigned. ", dom.br(), dom.a(attr.href('https://autoconfig.' + domainName(domain) + '/profile.mobileconfig?addresses=' + encodeURIComponent(addresses.join(',')) + '&name=' + encodeURIComponent(dest.FullName)), attr.download(''), 'Download .mobileconfig email account profile'), dom.br(), dom.a(attr.href('https://autoconfig.' + domainName(domain) + '/profile.mobileconfig.qrcode.png?addresses=' + encodeURIComponent(addresses.join(',')) + '&name=' + encodeURIComponent(dest.FullName)), attr.download(''), 'Open QR-code with link to .mobileconfig profile')));
|
||||
}), dom.br(), dom.br(), dom.br(), dom.p("Apple's mail applications don't do account autoconfiguration, and when adding an account it can choose defaults that don't work with modern email servers. Adding an account through a \"mobileconfig\" profile file can be more convenient: It contains the IMAP/SMTP settings such as host name, port, TLS, authentication mechanism and user name. This profile does not contain a login password. Opening the profile adds it under Profiles in System Preferences (macOS) or Settings (iOS), where you can install it. These profiles are not signed, so users will have to ignore the warnings about them being unsigned. ", dom.br(), dom.a(attr.href('https://autoconfig.' + domainName(acc.DNSDomain) + '/profile.mobileconfig?addresses=' + encodeURIComponent(addresses.join(',')) + '&name=' + encodeURIComponent(dest.FullName)), attr.download(''), 'Download .mobileconfig email account profile'), dom.br(), dom.a(attr.href('https://autoconfig.' + domainName(acc.DNSDomain) + '/profile.mobileconfig.qrcode.png?addresses=' + encodeURIComponent(addresses.join(',')) + '&name=' + encodeURIComponent(dest.FullName)), attr.download(''), 'Open QR-code with link to .mobileconfig profile')));
|
||||
};
|
||||
const init = async () => {
|
||||
let curhash;
|
||||
|
|
|
@ -213,7 +213,7 @@ const formatQuotaSize = (v: number) => {
|
|||
}
|
||||
|
||||
const index = async () => {
|
||||
const [accountFullName, domain, destinations, storageUsed, storageLimit] = await client.Account()
|
||||
const [acc, storageUsed, storageLimit] = await client.Account()
|
||||
|
||||
let fullNameForm: HTMLFormElement
|
||||
let fullNameFieldset: HTMLFieldSetElement
|
||||
|
@ -350,7 +350,7 @@ const index = async () => {
|
|||
dom.p('NOTE: Not all account settings can be configured through these pages yet. See the configuration file for more options.'),
|
||||
dom.div(
|
||||
'Default domain: ',
|
||||
domain.ASCII ? domainString(domain) : '(none)',
|
||||
acc.DNSDomain.ASCII ? domainString(acc.DNSDomain) : '(none)',
|
||||
),
|
||||
dom.br(),
|
||||
|
||||
|
@ -360,7 +360,7 @@ const index = async () => {
|
|||
style({display: 'inline-block'}),
|
||||
'Full name',
|
||||
dom.br(),
|
||||
fullName=dom.input(attr.value(accountFullName), attr.title('Name to use in From header when composing messages. Can be overridden per configured address.')),
|
||||
fullName=dom.input(attr.value(acc.FullName), attr.title('Name to use in From header when composing messages. Can be overridden per configured address.')),
|
||||
|
||||
),
|
||||
' ',
|
||||
|
@ -377,8 +377,8 @@ const index = async () => {
|
|||
|
||||
dom.h2('Addresses'),
|
||||
dom.ul(
|
||||
Object.entries(destinations || {}).length === 0 ? dom.li('(None, login disabled)') : [],
|
||||
Object.entries(destinations || {}).sort().map(t =>
|
||||
Object.entries(acc.Destinations || {}).length === 0 ? dom.li('(None, login disabled)') : [],
|
||||
Object.entries(acc.Destinations || {}).sort().map(t =>
|
||||
dom.li(
|
||||
dom.a(t[0], attr.href('#destinations/'+t[0])),
|
||||
t[0].startsWith('@') ? ' (catchall)' : [],
|
||||
|
@ -606,8 +606,8 @@ const index = async () => {
|
|||
}
|
||||
|
||||
const destination = async (name: string) => {
|
||||
const [_, domain, destinations] = await client.Account()
|
||||
let dest = destinations[name]
|
||||
const [acc] = await client.Account()
|
||||
let dest = (acc.Destinations || {})[name]
|
||||
if (!dest) {
|
||||
throw new Error('destination not found')
|
||||
}
|
||||
|
@ -725,7 +725,7 @@ const destination = async (name: string) => {
|
|||
let fullName: HTMLInputElement
|
||||
let saveButton: HTMLButtonElement
|
||||
|
||||
const addresses = [name, ...Object.keys(destinations || {}).filter(a => !a.startsWith('@') && a !== name)]
|
||||
const addresses = [name, ...Object.keys(acc.Destinations || {}).filter(a => !a.startsWith('@') && a !== name)]
|
||||
|
||||
dom._kids(page,
|
||||
crumbs(
|
||||
|
@ -811,9 +811,9 @@ const destination = async (name: string) => {
|
|||
dom.br(),
|
||||
dom.p("Apple's mail applications don't do account autoconfiguration, and when adding an account it can choose defaults that don't work with modern email servers. Adding an account through a \"mobileconfig\" profile file can be more convenient: It contains the IMAP/SMTP settings such as host name, port, TLS, authentication mechanism and user name. This profile does not contain a login password. Opening the profile adds it under Profiles in System Preferences (macOS) or Settings (iOS), where you can install it. These profiles are not signed, so users will have to ignore the warnings about them being unsigned. ",
|
||||
dom.br(),
|
||||
dom.a(attr.href('https://autoconfig.'+domainName(domain)+'/profile.mobileconfig?addresses='+encodeURIComponent(addresses.join(','))+'&name='+encodeURIComponent(dest.FullName)), attr.download(''), 'Download .mobileconfig email account profile'),
|
||||
dom.a(attr.href('https://autoconfig.'+domainName(acc.DNSDomain)+'/profile.mobileconfig?addresses='+encodeURIComponent(addresses.join(','))+'&name='+encodeURIComponent(dest.FullName)), attr.download(''), 'Download .mobileconfig email account profile'),
|
||||
dom.br(),
|
||||
dom.a(attr.href('https://autoconfig.'+domainName(domain)+'/profile.mobileconfig.qrcode.png?addresses='+encodeURIComponent(addresses.join(','))+'&name='+encodeURIComponent(dest.FullName)), attr.download(''), 'Open QR-code with link to .mobileconfig profile'),
|
||||
dom.a(attr.href('https://autoconfig.'+domainName(acc.DNSDomain)+'/profile.mobileconfig.qrcode.png?addresses='+encodeURIComponent(addresses.join(','))+'&name='+encodeURIComponent(dest.FullName)), attr.download(''), 'Open QR-code with link to .mobileconfig profile'),
|
||||
),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -216,11 +216,11 @@ func TestAccount(t *testing.T) {
|
|||
|
||||
api.SetPassword(ctx, "test1234")
|
||||
|
||||
fullName, _, dests, _, _ := api.Account(ctx)
|
||||
api.DestinationSave(ctx, "mjl☺@mox.example", dests["mjl☺@mox.example"], dests["mjl☺@mox.example"]) // todo: save modified value and compare it afterwards
|
||||
account, _, _ := api.Account(ctx)
|
||||
api.DestinationSave(ctx, "mjl☺@mox.example", account.Destinations["mjl☺@mox.example"], account.Destinations["mjl☺@mox.example"]) // todo: save modified value and compare it afterwards
|
||||
|
||||
api.AccountSaveFullName(ctx, fullName+" changed") // todo: check if value was changed
|
||||
api.AccountSaveFullName(ctx, fullName)
|
||||
api.AccountSaveFullName(ctx, account.FullName+" changed") // todo: check if value was changed
|
||||
api.AccountSaveFullName(ctx, account.FullName)
|
||||
|
||||
go ImportManage()
|
||||
|
||||
|
|
|
@ -68,26 +68,13 @@
|
|||
},
|
||||
{
|
||||
"Name": "Account",
|
||||
"Docs": "Account returns information about the account: full name, the default domain,\nand the destinations (keys are email addresses, or localparts to the default\ndomain). todo: replace with a function that returns the whole account, when\nsherpadoc understands unnamed struct fields.\nStorageUsed is the sum of the sizes of all messages, in bytes.\nStorageLimit is the maximum storage that can be used, or 0 if there is no limit.",
|
||||
"Docs": "Account returns information about the account.\nStorageUsed is the sum of the sizes of all messages, in bytes.\nStorageLimit is the maximum storage that can be used, or 0 if there is no limit.",
|
||||
"Params": [],
|
||||
"Returns": [
|
||||
{
|
||||
"Name": "fullName",
|
||||
"Name": "account",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "defaultDomain",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "destinations",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"Destination"
|
||||
"Account"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -172,22 +159,116 @@
|
|||
"Sections": [],
|
||||
"Structs": [
|
||||
{
|
||||
"Name": "Domain",
|
||||
"Docs": "Domain is a domain name, with one or more labels, with at least an ASCII\nrepresentation, and for IDNA non-ASCII domains a unicode representation.\nThe ASCII string must be used for DNS lookups. The strings do not have a\ntrailing dot. When using with StrictResolver, add the trailing dot.",
|
||||
"Name": "Account",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "ASCII",
|
||||
"Docs": "A non-unicode domain, e.g. with A-labels (xn--...) or NR-LDH (non-reserved letters/digits/hyphens) labels. Always in lower case. No trailing dot.",
|
||||
"Name": "Domain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Unicode",
|
||||
"Docs": "Name as U-labels, in Unicode NFC. Empty if this is an ASCII-only domain. No trailing dot.",
|
||||
"Name": "Description",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FullName",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Destinations",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"Destination"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "SubjectPass",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"SubjectPass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "QuotaMessageSize",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "RejectsMailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "KeepRejects",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AutomaticJunkFlags",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"AutomaticJunkFlags"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "JunkFilter",
|
||||
"Docs": "todo: sane defaults for junkfilter",
|
||||
"Typewords": [
|
||||
"nullable",
|
||||
"JunkFilter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MaxOutgoingMessagesPerDay",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MaxFirstTimeRecipientsPerDay",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "NoFirstTimeSenderDelay",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Routes",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"Route"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "DNSDomain",
|
||||
"Docs": "Parsed form of Domain.",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
@ -289,6 +370,187 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Domain",
|
||||
"Docs": "Domain is a domain name, with one or more labels, with at least an ASCII\nrepresentation, and for IDNA non-ASCII domains a unicode representation.\nThe ASCII string must be used for DNS lookups. The strings do not have a\ntrailing dot. When using with StrictResolver, add the trailing dot.",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "ASCII",
|
||||
"Docs": "A non-unicode domain, e.g. with A-labels (xn--...) or NR-LDH (non-reserved letters/digits/hyphens) labels. Always in lower case. No trailing dot.",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Unicode",
|
||||
"Docs": "Name as U-labels, in Unicode NFC. Empty if this is an ASCII-only domain. No trailing dot.",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "SubjectPass",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Period",
|
||||
"Docs": "todo: have a reasonable default for this?",
|
||||
"Typewords": [
|
||||
"int64"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AutomaticJunkFlags",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Enabled",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "JunkMailboxRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "NeutralMailboxRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "NotJunkMailboxRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "JunkFilter",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Threshold",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"float64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Onegrams",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Twograms",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Threegrams",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MaxPower",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"float64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "TopWords",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "IgnoreWords",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"float64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "RareWords",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Route",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "FromDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ToDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MinimumAttempts",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Transport",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FromDomainASCII",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ToDomainASCII",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ImportProgress",
|
||||
"Docs": "ImportProgress is returned after uploading a file to import.",
|
||||
|
|
|
@ -2,13 +2,22 @@
|
|||
|
||||
namespace api {
|
||||
|
||||
// Domain is a domain name, with one or more labels, with at least an ASCII
|
||||
// representation, and for IDNA non-ASCII domains a unicode representation.
|
||||
// The ASCII string must be used for DNS lookups. The strings do not have a
|
||||
// trailing dot. When using with StrictResolver, add the trailing dot.
|
||||
export interface Domain {
|
||||
ASCII: string // A non-unicode domain, e.g. with A-labels (xn--...) or NR-LDH (non-reserved letters/digits/hyphens) labels. Always in lower case. No trailing dot.
|
||||
Unicode: string // Name as U-labels, in Unicode NFC. Empty if this is an ASCII-only domain. No trailing dot.
|
||||
export interface Account {
|
||||
Domain: string
|
||||
Description: string
|
||||
FullName: string
|
||||
Destinations?: { [key: string]: Destination }
|
||||
SubjectPass: SubjectPass
|
||||
QuotaMessageSize: number
|
||||
RejectsMailbox: string
|
||||
KeepRejects: boolean
|
||||
AutomaticJunkFlags: AutomaticJunkFlags
|
||||
JunkFilter?: JunkFilter | null // todo: sane defaults for junkfilter
|
||||
MaxOutgoingMessagesPerDay: number
|
||||
MaxFirstTimeRecipientsPerDay: number
|
||||
NoFirstTimeSenderDelay: boolean
|
||||
Routes?: Route[] | null
|
||||
DNSDomain: Domain // Parsed form of Domain.
|
||||
}
|
||||
|
||||
export interface Destination {
|
||||
|
@ -29,6 +38,46 @@ export interface Ruleset {
|
|||
ListAllowDNSDomain: Domain
|
||||
}
|
||||
|
||||
// Domain is a domain name, with one or more labels, with at least an ASCII
|
||||
// representation, and for IDNA non-ASCII domains a unicode representation.
|
||||
// The ASCII string must be used for DNS lookups. The strings do not have a
|
||||
// trailing dot. When using with StrictResolver, add the trailing dot.
|
||||
export interface Domain {
|
||||
ASCII: string // A non-unicode domain, e.g. with A-labels (xn--...) or NR-LDH (non-reserved letters/digits/hyphens) labels. Always in lower case. No trailing dot.
|
||||
Unicode: string // Name as U-labels, in Unicode NFC. Empty if this is an ASCII-only domain. No trailing dot.
|
||||
}
|
||||
|
||||
export interface SubjectPass {
|
||||
Period: number // todo: have a reasonable default for this?
|
||||
}
|
||||
|
||||
export interface AutomaticJunkFlags {
|
||||
Enabled: boolean
|
||||
JunkMailboxRegexp: string
|
||||
NeutralMailboxRegexp: string
|
||||
NotJunkMailboxRegexp: string
|
||||
}
|
||||
|
||||
export interface JunkFilter {
|
||||
Threshold: number
|
||||
Onegrams: boolean
|
||||
Twograms: boolean
|
||||
Threegrams: boolean
|
||||
MaxPower: number
|
||||
TopWords: number
|
||||
IgnoreWords: number
|
||||
RareWords: number
|
||||
}
|
||||
|
||||
export interface Route {
|
||||
FromDomain?: string[] | null
|
||||
ToDomain?: string[] | null
|
||||
MinimumAttempts: number
|
||||
Transport: string
|
||||
FromDomainASCII?: string[] | null
|
||||
ToDomainASCII?: string[] | null
|
||||
}
|
||||
|
||||
// ImportProgress is returned after uploading a file to import.
|
||||
export interface ImportProgress {
|
||||
Token: string // For fetching progress, or cancelling an import.
|
||||
|
@ -36,21 +85,31 @@ export interface ImportProgress {
|
|||
|
||||
export type CSRFToken = string
|
||||
|
||||
export const structTypes: {[typename: string]: boolean} = {"Destination":true,"Domain":true,"ImportProgress":true,"Ruleset":true}
|
||||
export const structTypes: {[typename: string]: boolean} = {"Account":true,"AutomaticJunkFlags":true,"Destination":true,"Domain":true,"ImportProgress":true,"JunkFilter":true,"Route":true,"Ruleset":true,"SubjectPass":true}
|
||||
export const stringsTypes: {[typename: string]: boolean} = {"CSRFToken":true}
|
||||
export const intsTypes: {[typename: string]: boolean} = {}
|
||||
export const types: TypenameMap = {
|
||||
"Domain": {"Name":"Domain","Docs":"","Fields":[{"Name":"ASCII","Docs":"","Typewords":["string"]},{"Name":"Unicode","Docs":"","Typewords":["string"]}]},
|
||||
"Account": {"Name":"Account","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Description","Docs":"","Typewords":["string"]},{"Name":"FullName","Docs":"","Typewords":["string"]},{"Name":"Destinations","Docs":"","Typewords":["{}","Destination"]},{"Name":"SubjectPass","Docs":"","Typewords":["SubjectPass"]},{"Name":"QuotaMessageSize","Docs":"","Typewords":["int64"]},{"Name":"RejectsMailbox","Docs":"","Typewords":["string"]},{"Name":"KeepRejects","Docs":"","Typewords":["bool"]},{"Name":"AutomaticJunkFlags","Docs":"","Typewords":["AutomaticJunkFlags"]},{"Name":"JunkFilter","Docs":"","Typewords":["nullable","JunkFilter"]},{"Name":"MaxOutgoingMessagesPerDay","Docs":"","Typewords":["int32"]},{"Name":"MaxFirstTimeRecipientsPerDay","Docs":"","Typewords":["int32"]},{"Name":"NoFirstTimeSenderDelay","Docs":"","Typewords":["bool"]},{"Name":"Routes","Docs":"","Typewords":["[]","Route"]},{"Name":"DNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"Destination": {"Name":"Destination","Docs":"","Fields":[{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"Rulesets","Docs":"","Typewords":["[]","Ruleset"]},{"Name":"FullName","Docs":"","Typewords":["string"]}]},
|
||||
"Ruleset": {"Name":"Ruleset","Docs":"","Fields":[{"Name":"SMTPMailFromRegexp","Docs":"","Typewords":["string"]},{"Name":"VerifiedDomain","Docs":"","Typewords":["string"]},{"Name":"HeadersRegexp","Docs":"","Typewords":["{}","string"]},{"Name":"IsForward","Docs":"","Typewords":["bool"]},{"Name":"ListAllowDomain","Docs":"","Typewords":["string"]},{"Name":"AcceptRejectsToMailbox","Docs":"","Typewords":["string"]},{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"VerifiedDNSDomain","Docs":"","Typewords":["Domain"]},{"Name":"ListAllowDNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"Domain": {"Name":"Domain","Docs":"","Fields":[{"Name":"ASCII","Docs":"","Typewords":["string"]},{"Name":"Unicode","Docs":"","Typewords":["string"]}]},
|
||||
"SubjectPass": {"Name":"SubjectPass","Docs":"","Fields":[{"Name":"Period","Docs":"","Typewords":["int64"]}]},
|
||||
"AutomaticJunkFlags": {"Name":"AutomaticJunkFlags","Docs":"","Fields":[{"Name":"Enabled","Docs":"","Typewords":["bool"]},{"Name":"JunkMailboxRegexp","Docs":"","Typewords":["string"]},{"Name":"NeutralMailboxRegexp","Docs":"","Typewords":["string"]},{"Name":"NotJunkMailboxRegexp","Docs":"","Typewords":["string"]}]},
|
||||
"JunkFilter": {"Name":"JunkFilter","Docs":"","Fields":[{"Name":"Threshold","Docs":"","Typewords":["float64"]},{"Name":"Onegrams","Docs":"","Typewords":["bool"]},{"Name":"Twograms","Docs":"","Typewords":["bool"]},{"Name":"Threegrams","Docs":"","Typewords":["bool"]},{"Name":"MaxPower","Docs":"","Typewords":["float64"]},{"Name":"TopWords","Docs":"","Typewords":["int32"]},{"Name":"IgnoreWords","Docs":"","Typewords":["float64"]},{"Name":"RareWords","Docs":"","Typewords":["int32"]}]},
|
||||
"Route": {"Name":"Route","Docs":"","Fields":[{"Name":"FromDomain","Docs":"","Typewords":["[]","string"]},{"Name":"ToDomain","Docs":"","Typewords":["[]","string"]},{"Name":"MinimumAttempts","Docs":"","Typewords":["int32"]},{"Name":"Transport","Docs":"","Typewords":["string"]},{"Name":"FromDomainASCII","Docs":"","Typewords":["[]","string"]},{"Name":"ToDomainASCII","Docs":"","Typewords":["[]","string"]}]},
|
||||
"ImportProgress": {"Name":"ImportProgress","Docs":"","Fields":[{"Name":"Token","Docs":"","Typewords":["string"]}]},
|
||||
"CSRFToken": {"Name":"CSRFToken","Docs":"","Values":null},
|
||||
}
|
||||
|
||||
export const parser = {
|
||||
Domain: (v: any) => parse("Domain", v) as Domain,
|
||||
Account: (v: any) => parse("Account", v) as Account,
|
||||
Destination: (v: any) => parse("Destination", v) as Destination,
|
||||
Ruleset: (v: any) => parse("Ruleset", v) as Ruleset,
|
||||
Domain: (v: any) => parse("Domain", v) as Domain,
|
||||
SubjectPass: (v: any) => parse("SubjectPass", v) as SubjectPass,
|
||||
AutomaticJunkFlags: (v: any) => parse("AutomaticJunkFlags", v) as AutomaticJunkFlags,
|
||||
JunkFilter: (v: any) => parse("JunkFilter", v) as JunkFilter,
|
||||
Route: (v: any) => parse("Route", v) as Route,
|
||||
ImportProgress: (v: any) => parse("ImportProgress", v) as ImportProgress,
|
||||
CSRFToken: (v: any) => parse("CSRFToken", v) as CSRFToken,
|
||||
}
|
||||
|
@ -125,18 +184,15 @@ export class Client {
|
|||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as void
|
||||
}
|
||||
|
||||
// Account returns information about the account: full name, the default domain,
|
||||
// and the destinations (keys are email addresses, or localparts to the default
|
||||
// domain). todo: replace with a function that returns the whole account, when
|
||||
// sherpadoc understands unnamed struct fields.
|
||||
// Account returns information about the account.
|
||||
// StorageUsed is the sum of the sizes of all messages, in bytes.
|
||||
// StorageLimit is the maximum storage that can be used, or 0 if there is no limit.
|
||||
async Account(): Promise<[string, Domain, { [key: string]: Destination }, number, number]> {
|
||||
async Account(): Promise<[Account, number, number]> {
|
||||
const fn: string = "Account"
|
||||
const paramTypes: string[][] = []
|
||||
const returnTypes: string[][] = [["string"],["Domain"],["{}","Destination"],["int64"],["int64"]]
|
||||
const returnTypes: string[][] = [["Account"],["int64"],["int64"]]
|
||||
const params: any[] = []
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [string, Domain, { [key: string]: Destination }, number, number]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [Account, number, number]
|
||||
}
|
||||
|
||||
async AccountSaveFullName(fullName: string): Promise<void> {
|
||||
|
|
|
@ -1539,7 +1539,7 @@ func (Admin) Accounts(ctx context.Context) []string {
|
|||
}
|
||||
|
||||
// Account returns the parsed configuration of an account.
|
||||
func (Admin) Account(ctx context.Context, account string) (accountConfig map[string]any, diskUsage int64) {
|
||||
func (Admin) Account(ctx context.Context, account string) (accountConfig config.Account, diskUsage int64) {
|
||||
log := pkglog.WithContext(ctx)
|
||||
|
||||
acc, err := store.OpenAccount(log, account)
|
||||
|
@ -1565,14 +1565,7 @@ func (Admin) Account(ctx context.Context, account string) (accountConfig map[str
|
|||
xcheckf(ctx, err, "get disk usage")
|
||||
})
|
||||
|
||||
// todo: should change sherpa to understand config.Account directly, with its anonymous structs.
|
||||
buf, err := json.Marshal(ac)
|
||||
xcheckf(ctx, err, "marshal to json")
|
||||
r := map[string]any{}
|
||||
err = json.Unmarshal(buf, &r)
|
||||
xcheckf(ctx, err, "unmarshal from json")
|
||||
|
||||
return r, diskUsage
|
||||
return ac, diskUsage
|
||||
}
|
||||
|
||||
// ConfigFiles returns the paths and contents of the static and dynamic configuration files.
|
||||
|
|
|
@ -336,7 +336,7 @@ var api;
|
|||
SPFResult["SPFTemperror"] = "temperror";
|
||||
SPFResult["SPFPermerror"] = "permerror";
|
||||
})(SPFResult = api.SPFResult || (api.SPFResult = {}));
|
||||
api.structTypes = { "AuthResults": true, "AutoconfCheckResult": true, "AutodiscoverCheckResult": true, "AutodiscoverSRV": true, "CheckResult": true, "ClientConfigs": true, "ClientConfigsEntry": true, "DANECheckResult": true, "DKIMAuthResult": true, "DKIMCheckResult": true, "DKIMRecord": true, "DMARCCheckResult": true, "DMARCRecord": true, "DMARCSummary": true, "DNSSECResult": true, "DateRange": true, "Directive": true, "Domain": true, "DomainFeedback": true, "Evaluation": true, "EvaluationStat": true, "Extension": true, "FailureDetails": true, "Filter": true, "HoldRule": true, "IPDomain": true, "IPRevCheckResult": true, "Identifiers": true, "MTASTSCheckResult": true, "MTASTSRecord": true, "MX": true, "MXCheckResult": true, "Modifier": true, "Msg": true, "Pair": true, "Policy": true, "PolicyEvaluated": true, "PolicyOverrideReason": true, "PolicyPublished": true, "PolicyRecord": true, "Record": true, "Report": true, "ReportMetadata": true, "ReportRecord": true, "Result": true, "ResultPolicy": true, "Reverse": true, "Row": true, "SMTPAuth": true, "SPFAuthResult": true, "SPFCheckResult": true, "SPFRecord": true, "SRV": true, "SRVConfCheckResult": true, "STSMX": true, "Summary": true, "SuppressAddress": true, "TLSCheckResult": true, "TLSRPTCheckResult": true, "TLSRPTDateRange": true, "TLSRPTRecord": true, "TLSRPTSummary": true, "TLSRPTSuppressAddress": true, "TLSReportRecord": true, "TLSResult": true, "Transport": true, "TransportDirect": true, "TransportSMTP": true, "TransportSocks": true, "URI": true, "WebForward": true, "WebHandler": true, "WebRedirect": true, "WebStatic": true, "WebserverConfig": true };
|
||||
api.structTypes = { "Account": true, "AuthResults": true, "AutoconfCheckResult": true, "AutodiscoverCheckResult": true, "AutodiscoverSRV": true, "AutomaticJunkFlags": true, "CheckResult": true, "ClientConfigs": true, "ClientConfigsEntry": true, "DANECheckResult": true, "DKIMAuthResult": true, "DKIMCheckResult": true, "DKIMRecord": true, "DMARCCheckResult": true, "DMARCRecord": true, "DMARCSummary": true, "DNSSECResult": true, "DateRange": true, "Destination": true, "Directive": true, "Domain": true, "DomainFeedback": true, "Evaluation": true, "EvaluationStat": true, "Extension": true, "FailureDetails": true, "Filter": true, "HoldRule": true, "IPDomain": true, "IPRevCheckResult": true, "Identifiers": true, "JunkFilter": true, "MTASTSCheckResult": true, "MTASTSRecord": true, "MX": true, "MXCheckResult": true, "Modifier": true, "Msg": true, "Pair": true, "Policy": true, "PolicyEvaluated": true, "PolicyOverrideReason": true, "PolicyPublished": true, "PolicyRecord": true, "Record": true, "Report": true, "ReportMetadata": true, "ReportRecord": true, "Result": true, "ResultPolicy": true, "Reverse": true, "Route": true, "Row": true, "Ruleset": true, "SMTPAuth": true, "SPFAuthResult": true, "SPFCheckResult": true, "SPFRecord": true, "SRV": true, "SRVConfCheckResult": true, "STSMX": true, "SubjectPass": true, "Summary": true, "SuppressAddress": true, "TLSCheckResult": true, "TLSRPTCheckResult": true, "TLSRPTDateRange": true, "TLSRPTRecord": true, "TLSRPTSummary": true, "TLSRPTSuppressAddress": true, "TLSReportRecord": true, "TLSResult": true, "Transport": true, "TransportDirect": true, "TransportSMTP": true, "TransportSocks": true, "URI": true, "WebForward": true, "WebHandler": true, "WebRedirect": true, "WebStatic": true, "WebserverConfig": true };
|
||||
api.stringsTypes = { "Align": true, "Alignment": true, "CSRFToken": true, "DKIMResult": true, "DMARCPolicy": true, "DMARCResult": true, "Disposition": true, "IP": true, "Localpart": true, "Mode": true, "PolicyOverride": true, "PolicyType": true, "RUA": true, "ResultType": true, "SPFDomainScope": true, "SPFResult": true };
|
||||
api.intsTypes = {};
|
||||
api.types = {
|
||||
|
@ -371,6 +371,13 @@ var api;
|
|||
"AutoconfCheckResult": { "Name": "AutoconfCheckResult", "Docs": "", "Fields": [{ "Name": "ClientSettingsDomainIPs", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "IPs", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Errors", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Warnings", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Instructions", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"AutodiscoverCheckResult": { "Name": "AutodiscoverCheckResult", "Docs": "", "Fields": [{ "Name": "Records", "Docs": "", "Typewords": ["[]", "AutodiscoverSRV"] }, { "Name": "Errors", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Warnings", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "Instructions", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"AutodiscoverSRV": { "Name": "AutodiscoverSRV", "Docs": "", "Fields": [{ "Name": "Target", "Docs": "", "Typewords": ["string"] }, { "Name": "Port", "Docs": "", "Typewords": ["uint16"] }, { "Name": "Priority", "Docs": "", "Typewords": ["uint16"] }, { "Name": "Weight", "Docs": "", "Typewords": ["uint16"] }, { "Name": "IPs", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"Account": { "Name": "Account", "Docs": "", "Fields": [{ "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Description", "Docs": "", "Typewords": ["string"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }, { "Name": "Destinations", "Docs": "", "Typewords": ["{}", "Destination"] }, { "Name": "SubjectPass", "Docs": "", "Typewords": ["SubjectPass"] }, { "Name": "QuotaMessageSize", "Docs": "", "Typewords": ["int64"] }, { "Name": "RejectsMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "KeepRejects", "Docs": "", "Typewords": ["bool"] }, { "Name": "AutomaticJunkFlags", "Docs": "", "Typewords": ["AutomaticJunkFlags"] }, { "Name": "JunkFilter", "Docs": "", "Typewords": ["nullable", "JunkFilter"] }, { "Name": "MaxOutgoingMessagesPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "MaxFirstTimeRecipientsPerDay", "Docs": "", "Typewords": ["int32"] }, { "Name": "NoFirstTimeSenderDelay", "Docs": "", "Typewords": ["bool"] }, { "Name": "Routes", "Docs": "", "Typewords": ["[]", "Route"] }, { "Name": "DNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"Destination": { "Name": "Destination", "Docs": "", "Fields": [{ "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Rulesets", "Docs": "", "Typewords": ["[]", "Ruleset"] }, { "Name": "FullName", "Docs": "", "Typewords": ["string"] }] },
|
||||
"Ruleset": { "Name": "Ruleset", "Docs": "", "Fields": [{ "Name": "SMTPMailFromRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "VerifiedDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "HeadersRegexp", "Docs": "", "Typewords": ["{}", "string"] }, { "Name": "IsForward", "Docs": "", "Typewords": ["bool"] }, { "Name": "ListAllowDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "AcceptRejectsToMailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "Mailbox", "Docs": "", "Typewords": ["string"] }, { "Name": "VerifiedDNSDomain", "Docs": "", "Typewords": ["Domain"] }, { "Name": "ListAllowDNSDomain", "Docs": "", "Typewords": ["Domain"] }] },
|
||||
"SubjectPass": { "Name": "SubjectPass", "Docs": "", "Fields": [{ "Name": "Period", "Docs": "", "Typewords": ["int64"] }] },
|
||||
"AutomaticJunkFlags": { "Name": "AutomaticJunkFlags", "Docs": "", "Fields": [{ "Name": "Enabled", "Docs": "", "Typewords": ["bool"] }, { "Name": "JunkMailboxRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "NeutralMailboxRegexp", "Docs": "", "Typewords": ["string"] }, { "Name": "NotJunkMailboxRegexp", "Docs": "", "Typewords": ["string"] }] },
|
||||
"JunkFilter": { "Name": "JunkFilter", "Docs": "", "Fields": [{ "Name": "Threshold", "Docs": "", "Typewords": ["float64"] }, { "Name": "Onegrams", "Docs": "", "Typewords": ["bool"] }, { "Name": "Twograms", "Docs": "", "Typewords": ["bool"] }, { "Name": "Threegrams", "Docs": "", "Typewords": ["bool"] }, { "Name": "MaxPower", "Docs": "", "Typewords": ["float64"] }, { "Name": "TopWords", "Docs": "", "Typewords": ["int32"] }, { "Name": "IgnoreWords", "Docs": "", "Typewords": ["float64"] }, { "Name": "RareWords", "Docs": "", "Typewords": ["int32"] }] },
|
||||
"Route": { "Name": "Route", "Docs": "", "Fields": [{ "Name": "FromDomain", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "ToDomain", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "MinimumAttempts", "Docs": "", "Typewords": ["int32"] }, { "Name": "Transport", "Docs": "", "Typewords": ["string"] }, { "Name": "FromDomainASCII", "Docs": "", "Typewords": ["[]", "string"] }, { "Name": "ToDomainASCII", "Docs": "", "Typewords": ["[]", "string"] }] },
|
||||
"PolicyRecord": { "Name": "PolicyRecord", "Docs": "", "Fields": [{ "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "Inserted", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "ValidEnd", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "LastUpdate", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "LastUse", "Docs": "", "Typewords": ["timestamp"] }, { "Name": "Backoff", "Docs": "", "Typewords": ["bool"] }, { "Name": "RecordID", "Docs": "", "Typewords": ["string"] }, { "Name": "Version", "Docs": "", "Typewords": ["string"] }, { "Name": "Mode", "Docs": "", "Typewords": ["Mode"] }, { "Name": "MX", "Docs": "", "Typewords": ["[]", "STSMX"] }, { "Name": "MaxAgeSeconds", "Docs": "", "Typewords": ["int32"] }, { "Name": "Extensions", "Docs": "", "Typewords": ["[]", "Pair"] }, { "Name": "PolicyText", "Docs": "", "Typewords": ["string"] }] },
|
||||
"TLSReportRecord": { "Name": "TLSReportRecord", "Docs": "", "Fields": [{ "Name": "ID", "Docs": "", "Typewords": ["int64"] }, { "Name": "Domain", "Docs": "", "Typewords": ["string"] }, { "Name": "FromDomain", "Docs": "", "Typewords": ["string"] }, { "Name": "MailFrom", "Docs": "", "Typewords": ["string"] }, { "Name": "HostReport", "Docs": "", "Typewords": ["bool"] }, { "Name": "Report", "Docs": "", "Typewords": ["Report"] }] },
|
||||
"Report": { "Name": "Report", "Docs": "", "Fields": [{ "Name": "OrganizationName", "Docs": "", "Typewords": ["string"] }, { "Name": "DateRange", "Docs": "", "Typewords": ["TLSRPTDateRange"] }, { "Name": "ContactInfo", "Docs": "", "Typewords": ["string"] }, { "Name": "ReportID", "Docs": "", "Typewords": ["string"] }, { "Name": "Policies", "Docs": "", "Typewords": ["[]", "Result"] }] },
|
||||
|
@ -464,6 +471,13 @@ var api;
|
|||
AutoconfCheckResult: (v) => api.parse("AutoconfCheckResult", v),
|
||||
AutodiscoverCheckResult: (v) => api.parse("AutodiscoverCheckResult", v),
|
||||
AutodiscoverSRV: (v) => api.parse("AutodiscoverSRV", v),
|
||||
Account: (v) => api.parse("Account", v),
|
||||
Destination: (v) => api.parse("Destination", v),
|
||||
Ruleset: (v) => api.parse("Ruleset", v),
|
||||
SubjectPass: (v) => api.parse("SubjectPass", v),
|
||||
AutomaticJunkFlags: (v) => api.parse("AutomaticJunkFlags", v),
|
||||
JunkFilter: (v) => api.parse("JunkFilter", v),
|
||||
Route: (v) => api.parse("Route", v),
|
||||
PolicyRecord: (v) => api.parse("PolicyRecord", v),
|
||||
TLSReportRecord: (v) => api.parse("TLSReportRecord", v),
|
||||
Report: (v) => api.parse("Report", v),
|
||||
|
@ -629,7 +643,7 @@ var api;
|
|||
async Account(account) {
|
||||
const fn = "Account";
|
||||
const paramTypes = [["string"]];
|
||||
const returnTypes = [["{}", "any"], ["int64"]];
|
||||
const returnTypes = [["Account"], ["int64"]];
|
||||
const params = [account];
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params);
|
||||
}
|
||||
|
@ -1883,7 +1897,7 @@ const account = async (name) => {
|
|||
await check(fieldset, client.AddressAdd(address, name));
|
||||
form.reset();
|
||||
window.location.reload(); // todo: only reload the destinations
|
||||
}, fieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), dom.span('Localpart', attr.title('The localpart is the part before the "@"-sign of an email address. If empty, a catchall address is configured for the domain.')), dom.br(), localpart = dom.input()), '@', dom.label(style({ display: 'inline-block' }), dom.span('Domain'), dom.br(), domain = dom.select((domains || []).map(d => dom.option(domainName(d), domainName(d) === config.Domain ? attr.selected('') : [])))), ' ', dom.submitbutton('Add address'))), dom.br(), dom.h2('Settings'), dom.form(fieldsetSettings = dom.fieldset(dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum outgoing messages per day', attr.title('Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000. MaxOutgoingMessagesPerDay in configuration file.')), dom.br(), maxOutgoingMessagesPerDay = dom.input(attr.type('number'), attr.required(''), attr.value(config.MaxOutgoingMessagesPerDay || 1000))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum first-time recipients per day', attr.title('Maximum number of first-time recipients in outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 200. MaxFirstTimeRecipientsPerDay in configuration file.')), dom.br(), maxFirstTimeRecipientsPerDay = dom.input(attr.type('number'), attr.required(''), attr.value(config.MaxFirstTimeRecipientsPerDay || 200))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Disk usage quota: Maximum total message size ', attr.title('Default maximum total message size in bytes for the account, overriding any globally configured default maximum size if non-zero. A negative value can be used to have no limit in case there is a limit by default. Attempting to add new messages to an account beyond its maximum total size will result in an error. Useful to prevent a single account from filling storage.')), dom.br(), quotaMessageSize = dom.input(attr.value(formatQuotaSize(config.QuotaMessageSize))), ' Current usage is ', formatQuotaSize(Math.floor(diskUsage / (1024 * 1024)) * 1024 * 1024), '.'), dom.div(style({ display: 'block', marginBottom: '.5ex' }), dom.label(firstTimeSenderDelay = dom.input(attr.type('checkbox'), config.NoFirstTimeSenderDelay ? [] : attr.checked('')), ' ', dom.span('Delay deliveries from first-time senders.', attr.title('To slow down potential spammers, when the message is misclassified as non-junk. Turning off the delay can be useful when the account processes messages automatically and needs fast responses.')))), dom.submitbutton('Save')), async function submit(e) {
|
||||
}, fieldset = dom.fieldset(dom.label(style({ display: 'inline-block' }), dom.span('Localpart', attr.title('The localpart is the part before the "@"-sign of an email address. If empty, a catchall address is configured for the domain.')), dom.br(), localpart = dom.input()), '@', dom.label(style({ display: 'inline-block' }), dom.span('Domain'), dom.br(), domain = dom.select((domains || []).map(d => dom.option(domainName(d), domainName(d) === config.Domain ? attr.selected('') : [])))), ' ', dom.submitbutton('Add address'))), dom.br(), dom.h2('Settings'), dom.form(fieldsetSettings = dom.fieldset(dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum outgoing messages per day', attr.title('Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000. MaxOutgoingMessagesPerDay in configuration file.')), dom.br(), maxOutgoingMessagesPerDay = dom.input(attr.type('number'), attr.required(''), attr.value('' + (config.MaxOutgoingMessagesPerDay || 1000)))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Maximum first-time recipients per day', attr.title('Maximum number of first-time recipients in outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 200. MaxFirstTimeRecipientsPerDay in configuration file.')), dom.br(), maxFirstTimeRecipientsPerDay = dom.input(attr.type('number'), attr.required(''), attr.value('' + (config.MaxFirstTimeRecipientsPerDay || 200)))), dom.label(style({ display: 'block', marginBottom: '.5ex' }), dom.span('Disk usage quota: Maximum total message size ', attr.title('Default maximum total message size in bytes for the account, overriding any globally configured default maximum size if non-zero. A negative value can be used to have no limit in case there is a limit by default. Attempting to add new messages to an account beyond its maximum total size will result in an error. Useful to prevent a single account from filling storage.')), dom.br(), quotaMessageSize = dom.input(attr.value(formatQuotaSize(config.QuotaMessageSize))), ' Current usage is ', formatQuotaSize(Math.floor(diskUsage / (1024 * 1024)) * 1024 * 1024), '.'), dom.div(style({ display: 'block', marginBottom: '.5ex' }), dom.label(firstTimeSenderDelay = dom.input(attr.type('checkbox'), config.NoFirstTimeSenderDelay ? [] : attr.checked('')), ' ', dom.span('Delay deliveries from first-time senders.', attr.title('To slow down potential spammers, when the message is misclassified as non-junk. Turning off the delay can be useful when the account processes messages automatically and needs fast responses.')))), dom.submitbutton('Save')), async function submit(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
await check(fieldsetSettings, client.AccountSettingsSave(name, parseInt(maxOutgoingMessagesPerDay.value) || 0, parseInt(maxFirstTimeRecipientsPerDay.value) || 0, xparseSize(quotaMessageSize.value), firstTimeSenderDelay.checked));
|
||||
|
|
|
@ -709,13 +709,13 @@ const account = async (name: string) => {
|
|||
style({display: 'block', marginBottom: '.5ex'}),
|
||||
dom.span('Maximum outgoing messages per day', attr.title('Maximum number of outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 1000. MaxOutgoingMessagesPerDay in configuration file.')),
|
||||
dom.br(),
|
||||
maxOutgoingMessagesPerDay=dom.input(attr.type('number'), attr.required(''), attr.value(config.MaxOutgoingMessagesPerDay || 1000)),
|
||||
maxOutgoingMessagesPerDay=dom.input(attr.type('number'), attr.required(''), attr.value(''+(config.MaxOutgoingMessagesPerDay || 1000))),
|
||||
),
|
||||
dom.label(
|
||||
style({display: 'block', marginBottom: '.5ex'}),
|
||||
dom.span('Maximum first-time recipients per day', attr.title('Maximum number of first-time recipients in outgoing messages for this account in a 24 hour window. This limits the damage to recipients and the reputation of this mail server in case of account compromise. Default 200. MaxFirstTimeRecipientsPerDay in configuration file.')),
|
||||
dom.br(),
|
||||
maxFirstTimeRecipientsPerDay=dom.input(attr.type('number'), attr.required(''), attr.value(config.MaxFirstTimeRecipientsPerDay || 200)),
|
||||
maxFirstTimeRecipientsPerDay=dom.input(attr.type('number'), attr.required(''), attr.value(''+(config.MaxFirstTimeRecipientsPerDay || 200))),
|
||||
),
|
||||
dom.label(
|
||||
style({display: 'block', marginBottom: '.5ex'}),
|
||||
|
|
|
@ -171,8 +171,7 @@
|
|||
{
|
||||
"Name": "accountConfig",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"any"
|
||||
"Account"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -2623,6 +2622,379 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Account",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Domain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Description",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FullName",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Destinations",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"Destination"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "SubjectPass",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"SubjectPass"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "QuotaMessageSize",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "RejectsMailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "KeepRejects",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AutomaticJunkFlags",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"AutomaticJunkFlags"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "JunkFilter",
|
||||
"Docs": "todo: sane defaults for junkfilter",
|
||||
"Typewords": [
|
||||
"nullable",
|
||||
"JunkFilter"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MaxOutgoingMessagesPerDay",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MaxFirstTimeRecipientsPerDay",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "NoFirstTimeSenderDelay",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Routes",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"Route"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "DNSDomain",
|
||||
"Docs": "Parsed form of Domain.",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Destination",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Mailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Rulesets",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"Ruleset"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FullName",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Ruleset",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "SMTPMailFromRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerifiedDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "HeadersRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"{}",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "IsForward",
|
||||
"Docs": "todo: once we implement ARC, we can use dkim domains that we cannot verify but that the arc-verified forwarding mail server was able to verify.",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListAllowDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AcceptRejectsToMailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Mailbox",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "VerifiedDNSDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ListAllowDNSDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"Domain"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "SubjectPass",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Period",
|
||||
"Docs": "todo: have a reasonable default for this?",
|
||||
"Typewords": [
|
||||
"int64"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "AutomaticJunkFlags",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Enabled",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "JunkMailboxRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "NeutralMailboxRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "NotJunkMailboxRegexp",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "JunkFilter",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "Threshold",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"float64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Onegrams",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Twograms",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Threegrams",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"bool"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MaxPower",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"float64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "TopWords",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "IgnoreWords",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"float64"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "RareWords",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Route",
|
||||
"Docs": "",
|
||||
"Fields": [
|
||||
{
|
||||
"Name": "FromDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ToDomain",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "MinimumAttempts",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"int32"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "Transport",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "FromDomainASCII",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "ToDomainASCII",
|
||||
"Docs": "",
|
||||
"Typewords": [
|
||||
"[]",
|
||||
"string"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"Name": "PolicyRecord",
|
||||
"Docs": "PolicyRecord is a cached policy or absence of a policy.",
|
||||
|
|
|
@ -266,6 +266,73 @@ export interface AutodiscoverSRV {
|
|||
IPs?: string[] | null
|
||||
}
|
||||
|
||||
export interface Account {
|
||||
Domain: string
|
||||
Description: string
|
||||
FullName: string
|
||||
Destinations?: { [key: string]: Destination }
|
||||
SubjectPass: SubjectPass
|
||||
QuotaMessageSize: number
|
||||
RejectsMailbox: string
|
||||
KeepRejects: boolean
|
||||
AutomaticJunkFlags: AutomaticJunkFlags
|
||||
JunkFilter?: JunkFilter | null // todo: sane defaults for junkfilter
|
||||
MaxOutgoingMessagesPerDay: number
|
||||
MaxFirstTimeRecipientsPerDay: number
|
||||
NoFirstTimeSenderDelay: boolean
|
||||
Routes?: Route[] | null
|
||||
DNSDomain: Domain // Parsed form of Domain.
|
||||
}
|
||||
|
||||
export interface Destination {
|
||||
Mailbox: string
|
||||
Rulesets?: Ruleset[] | null
|
||||
FullName: string
|
||||
}
|
||||
|
||||
export interface Ruleset {
|
||||
SMTPMailFromRegexp: string
|
||||
VerifiedDomain: string
|
||||
HeadersRegexp?: { [key: string]: string }
|
||||
IsForward: boolean // todo: once we implement ARC, we can use dkim domains that we cannot verify but that the arc-verified forwarding mail server was able to verify.
|
||||
ListAllowDomain: string
|
||||
AcceptRejectsToMailbox: string
|
||||
Mailbox: string
|
||||
VerifiedDNSDomain: Domain
|
||||
ListAllowDNSDomain: Domain
|
||||
}
|
||||
|
||||
export interface SubjectPass {
|
||||
Period: number // todo: have a reasonable default for this?
|
||||
}
|
||||
|
||||
export interface AutomaticJunkFlags {
|
||||
Enabled: boolean
|
||||
JunkMailboxRegexp: string
|
||||
NeutralMailboxRegexp: string
|
||||
NotJunkMailboxRegexp: string
|
||||
}
|
||||
|
||||
export interface JunkFilter {
|
||||
Threshold: number
|
||||
Onegrams: boolean
|
||||
Twograms: boolean
|
||||
Threegrams: boolean
|
||||
MaxPower: number
|
||||
TopWords: number
|
||||
IgnoreWords: number
|
||||
RareWords: number
|
||||
}
|
||||
|
||||
export interface Route {
|
||||
FromDomain?: string[] | null
|
||||
ToDomain?: string[] | null
|
||||
MinimumAttempts: number
|
||||
Transport: string
|
||||
FromDomainASCII?: string[] | null
|
||||
ToDomainASCII?: string[] | null
|
||||
}
|
||||
|
||||
// PolicyRecord is a cached policy or absence of a policy.
|
||||
export interface PolicyRecord {
|
||||
Domain: string // Domain name, with unicode characters.
|
||||
|
@ -816,7 +883,7 @@ export type Localpart = string
|
|||
// be an IPv4 address.
|
||||
export type IP = string
|
||||
|
||||
export const structTypes: {[typename: string]: boolean} = {"AuthResults":true,"AutoconfCheckResult":true,"AutodiscoverCheckResult":true,"AutodiscoverSRV":true,"CheckResult":true,"ClientConfigs":true,"ClientConfigsEntry":true,"DANECheckResult":true,"DKIMAuthResult":true,"DKIMCheckResult":true,"DKIMRecord":true,"DMARCCheckResult":true,"DMARCRecord":true,"DMARCSummary":true,"DNSSECResult":true,"DateRange":true,"Directive":true,"Domain":true,"DomainFeedback":true,"Evaluation":true,"EvaluationStat":true,"Extension":true,"FailureDetails":true,"Filter":true,"HoldRule":true,"IPDomain":true,"IPRevCheckResult":true,"Identifiers":true,"MTASTSCheckResult":true,"MTASTSRecord":true,"MX":true,"MXCheckResult":true,"Modifier":true,"Msg":true,"Pair":true,"Policy":true,"PolicyEvaluated":true,"PolicyOverrideReason":true,"PolicyPublished":true,"PolicyRecord":true,"Record":true,"Report":true,"ReportMetadata":true,"ReportRecord":true,"Result":true,"ResultPolicy":true,"Reverse":true,"Row":true,"SMTPAuth":true,"SPFAuthResult":true,"SPFCheckResult":true,"SPFRecord":true,"SRV":true,"SRVConfCheckResult":true,"STSMX":true,"Summary":true,"SuppressAddress":true,"TLSCheckResult":true,"TLSRPTCheckResult":true,"TLSRPTDateRange":true,"TLSRPTRecord":true,"TLSRPTSummary":true,"TLSRPTSuppressAddress":true,"TLSReportRecord":true,"TLSResult":true,"Transport":true,"TransportDirect":true,"TransportSMTP":true,"TransportSocks":true,"URI":true,"WebForward":true,"WebHandler":true,"WebRedirect":true,"WebStatic":true,"WebserverConfig":true}
|
||||
export const structTypes: {[typename: string]: boolean} = {"Account":true,"AuthResults":true,"AutoconfCheckResult":true,"AutodiscoverCheckResult":true,"AutodiscoverSRV":true,"AutomaticJunkFlags":true,"CheckResult":true,"ClientConfigs":true,"ClientConfigsEntry":true,"DANECheckResult":true,"DKIMAuthResult":true,"DKIMCheckResult":true,"DKIMRecord":true,"DMARCCheckResult":true,"DMARCRecord":true,"DMARCSummary":true,"DNSSECResult":true,"DateRange":true,"Destination":true,"Directive":true,"Domain":true,"DomainFeedback":true,"Evaluation":true,"EvaluationStat":true,"Extension":true,"FailureDetails":true,"Filter":true,"HoldRule":true,"IPDomain":true,"IPRevCheckResult":true,"Identifiers":true,"JunkFilter":true,"MTASTSCheckResult":true,"MTASTSRecord":true,"MX":true,"MXCheckResult":true,"Modifier":true,"Msg":true,"Pair":true,"Policy":true,"PolicyEvaluated":true,"PolicyOverrideReason":true,"PolicyPublished":true,"PolicyRecord":true,"Record":true,"Report":true,"ReportMetadata":true,"ReportRecord":true,"Result":true,"ResultPolicy":true,"Reverse":true,"Route":true,"Row":true,"Ruleset":true,"SMTPAuth":true,"SPFAuthResult":true,"SPFCheckResult":true,"SPFRecord":true,"SRV":true,"SRVConfCheckResult":true,"STSMX":true,"SubjectPass":true,"Summary":true,"SuppressAddress":true,"TLSCheckResult":true,"TLSRPTCheckResult":true,"TLSRPTDateRange":true,"TLSRPTRecord":true,"TLSRPTSummary":true,"TLSRPTSuppressAddress":true,"TLSReportRecord":true,"TLSResult":true,"Transport":true,"TransportDirect":true,"TransportSMTP":true,"TransportSocks":true,"URI":true,"WebForward":true,"WebHandler":true,"WebRedirect":true,"WebStatic":true,"WebserverConfig":true}
|
||||
export const stringsTypes: {[typename: string]: boolean} = {"Align":true,"Alignment":true,"CSRFToken":true,"DKIMResult":true,"DMARCPolicy":true,"DMARCResult":true,"Disposition":true,"IP":true,"Localpart":true,"Mode":true,"PolicyOverride":true,"PolicyType":true,"RUA":true,"ResultType":true,"SPFDomainScope":true,"SPFResult":true}
|
||||
export const intsTypes: {[typename: string]: boolean} = {}
|
||||
export const types: TypenameMap = {
|
||||
|
@ -851,6 +918,13 @@ export const types: TypenameMap = {
|
|||
"AutoconfCheckResult": {"Name":"AutoconfCheckResult","Docs":"","Fields":[{"Name":"ClientSettingsDomainIPs","Docs":"","Typewords":["[]","string"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
|
||||
"AutodiscoverCheckResult": {"Name":"AutodiscoverCheckResult","Docs":"","Fields":[{"Name":"Records","Docs":"","Typewords":["[]","AutodiscoverSRV"]},{"Name":"Errors","Docs":"","Typewords":["[]","string"]},{"Name":"Warnings","Docs":"","Typewords":["[]","string"]},{"Name":"Instructions","Docs":"","Typewords":["[]","string"]}]},
|
||||
"AutodiscoverSRV": {"Name":"AutodiscoverSRV","Docs":"","Fields":[{"Name":"Target","Docs":"","Typewords":["string"]},{"Name":"Port","Docs":"","Typewords":["uint16"]},{"Name":"Priority","Docs":"","Typewords":["uint16"]},{"Name":"Weight","Docs":"","Typewords":["uint16"]},{"Name":"IPs","Docs":"","Typewords":["[]","string"]}]},
|
||||
"Account": {"Name":"Account","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Description","Docs":"","Typewords":["string"]},{"Name":"FullName","Docs":"","Typewords":["string"]},{"Name":"Destinations","Docs":"","Typewords":["{}","Destination"]},{"Name":"SubjectPass","Docs":"","Typewords":["SubjectPass"]},{"Name":"QuotaMessageSize","Docs":"","Typewords":["int64"]},{"Name":"RejectsMailbox","Docs":"","Typewords":["string"]},{"Name":"KeepRejects","Docs":"","Typewords":["bool"]},{"Name":"AutomaticJunkFlags","Docs":"","Typewords":["AutomaticJunkFlags"]},{"Name":"JunkFilter","Docs":"","Typewords":["nullable","JunkFilter"]},{"Name":"MaxOutgoingMessagesPerDay","Docs":"","Typewords":["int32"]},{"Name":"MaxFirstTimeRecipientsPerDay","Docs":"","Typewords":["int32"]},{"Name":"NoFirstTimeSenderDelay","Docs":"","Typewords":["bool"]},{"Name":"Routes","Docs":"","Typewords":["[]","Route"]},{"Name":"DNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"Destination": {"Name":"Destination","Docs":"","Fields":[{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"Rulesets","Docs":"","Typewords":["[]","Ruleset"]},{"Name":"FullName","Docs":"","Typewords":["string"]}]},
|
||||
"Ruleset": {"Name":"Ruleset","Docs":"","Fields":[{"Name":"SMTPMailFromRegexp","Docs":"","Typewords":["string"]},{"Name":"VerifiedDomain","Docs":"","Typewords":["string"]},{"Name":"HeadersRegexp","Docs":"","Typewords":["{}","string"]},{"Name":"IsForward","Docs":"","Typewords":["bool"]},{"Name":"ListAllowDomain","Docs":"","Typewords":["string"]},{"Name":"AcceptRejectsToMailbox","Docs":"","Typewords":["string"]},{"Name":"Mailbox","Docs":"","Typewords":["string"]},{"Name":"VerifiedDNSDomain","Docs":"","Typewords":["Domain"]},{"Name":"ListAllowDNSDomain","Docs":"","Typewords":["Domain"]}]},
|
||||
"SubjectPass": {"Name":"SubjectPass","Docs":"","Fields":[{"Name":"Period","Docs":"","Typewords":["int64"]}]},
|
||||
"AutomaticJunkFlags": {"Name":"AutomaticJunkFlags","Docs":"","Fields":[{"Name":"Enabled","Docs":"","Typewords":["bool"]},{"Name":"JunkMailboxRegexp","Docs":"","Typewords":["string"]},{"Name":"NeutralMailboxRegexp","Docs":"","Typewords":["string"]},{"Name":"NotJunkMailboxRegexp","Docs":"","Typewords":["string"]}]},
|
||||
"JunkFilter": {"Name":"JunkFilter","Docs":"","Fields":[{"Name":"Threshold","Docs":"","Typewords":["float64"]},{"Name":"Onegrams","Docs":"","Typewords":["bool"]},{"Name":"Twograms","Docs":"","Typewords":["bool"]},{"Name":"Threegrams","Docs":"","Typewords":["bool"]},{"Name":"MaxPower","Docs":"","Typewords":["float64"]},{"Name":"TopWords","Docs":"","Typewords":["int32"]},{"Name":"IgnoreWords","Docs":"","Typewords":["float64"]},{"Name":"RareWords","Docs":"","Typewords":["int32"]}]},
|
||||
"Route": {"Name":"Route","Docs":"","Fields":[{"Name":"FromDomain","Docs":"","Typewords":["[]","string"]},{"Name":"ToDomain","Docs":"","Typewords":["[]","string"]},{"Name":"MinimumAttempts","Docs":"","Typewords":["int32"]},{"Name":"Transport","Docs":"","Typewords":["string"]},{"Name":"FromDomainASCII","Docs":"","Typewords":["[]","string"]},{"Name":"ToDomainASCII","Docs":"","Typewords":["[]","string"]}]},
|
||||
"PolicyRecord": {"Name":"PolicyRecord","Docs":"","Fields":[{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"Inserted","Docs":"","Typewords":["timestamp"]},{"Name":"ValidEnd","Docs":"","Typewords":["timestamp"]},{"Name":"LastUpdate","Docs":"","Typewords":["timestamp"]},{"Name":"LastUse","Docs":"","Typewords":["timestamp"]},{"Name":"Backoff","Docs":"","Typewords":["bool"]},{"Name":"RecordID","Docs":"","Typewords":["string"]},{"Name":"Version","Docs":"","Typewords":["string"]},{"Name":"Mode","Docs":"","Typewords":["Mode"]},{"Name":"MX","Docs":"","Typewords":["[]","STSMX"]},{"Name":"MaxAgeSeconds","Docs":"","Typewords":["int32"]},{"Name":"Extensions","Docs":"","Typewords":["[]","Pair"]},{"Name":"PolicyText","Docs":"","Typewords":["string"]}]},
|
||||
"TLSReportRecord": {"Name":"TLSReportRecord","Docs":"","Fields":[{"Name":"ID","Docs":"","Typewords":["int64"]},{"Name":"Domain","Docs":"","Typewords":["string"]},{"Name":"FromDomain","Docs":"","Typewords":["string"]},{"Name":"MailFrom","Docs":"","Typewords":["string"]},{"Name":"HostReport","Docs":"","Typewords":["bool"]},{"Name":"Report","Docs":"","Typewords":["Report"]}]},
|
||||
"Report": {"Name":"Report","Docs":"","Fields":[{"Name":"OrganizationName","Docs":"","Typewords":["string"]},{"Name":"DateRange","Docs":"","Typewords":["TLSRPTDateRange"]},{"Name":"ContactInfo","Docs":"","Typewords":["string"]},{"Name":"ReportID","Docs":"","Typewords":["string"]},{"Name":"Policies","Docs":"","Typewords":["[]","Result"]}]},
|
||||
|
@ -945,6 +1019,13 @@ export const parser = {
|
|||
AutoconfCheckResult: (v: any) => parse("AutoconfCheckResult", v) as AutoconfCheckResult,
|
||||
AutodiscoverCheckResult: (v: any) => parse("AutodiscoverCheckResult", v) as AutodiscoverCheckResult,
|
||||
AutodiscoverSRV: (v: any) => parse("AutodiscoverSRV", v) as AutodiscoverSRV,
|
||||
Account: (v: any) => parse("Account", v) as Account,
|
||||
Destination: (v: any) => parse("Destination", v) as Destination,
|
||||
Ruleset: (v: any) => parse("Ruleset", v) as Ruleset,
|
||||
SubjectPass: (v: any) => parse("SubjectPass", v) as SubjectPass,
|
||||
AutomaticJunkFlags: (v: any) => parse("AutomaticJunkFlags", v) as AutomaticJunkFlags,
|
||||
JunkFilter: (v: any) => parse("JunkFilter", v) as JunkFilter,
|
||||
Route: (v: any) => parse("Route", v) as Route,
|
||||
PolicyRecord: (v: any) => parse("PolicyRecord", v) as PolicyRecord,
|
||||
TLSReportRecord: (v: any) => parse("TLSReportRecord", v) as TLSReportRecord,
|
||||
Report: (v: any) => parse("Report", v) as Report,
|
||||
|
@ -1122,12 +1203,12 @@ export class Client {
|
|||
}
|
||||
|
||||
// Account returns the parsed configuration of an account.
|
||||
async Account(account: string): Promise<[{ [key: string]: any }, number]> {
|
||||
async Account(account: string): Promise<[Account, number]> {
|
||||
const fn: string = "Account"
|
||||
const paramTypes: string[][] = [["string"]]
|
||||
const returnTypes: string[][] = [["{}","any"],["int64"]]
|
||||
const returnTypes: string[][] = [["Account"],["int64"]]
|
||||
const params: any[] = [account]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [{ [key: string]: any }, number]
|
||||
return await _sherpaCall(this.baseURL, this.authState, { ...this.options }, paramTypes, returnTypes, fn, params) as [Account, number]
|
||||
}
|
||||
|
||||
// ConfigFiles returns the paths and contents of the static and dynamic configuration files.
|
||||
|
|
Loading…
Reference in a new issue