diff --git a/irc/accounts.go b/irc/accounts.go index 375668cd..b9082083 100644 --- a/irc/accounts.go +++ b/irc/accounts.go @@ -378,7 +378,7 @@ func (am *AccountManager) Register(client *Client, account string, callbackNames return err } - registeredTimeStr := strconv.FormatInt(time.Now().Unix(), 10) + registeredTimeStr := strconv.FormatInt(time.Now().UnixNano(), 10) callbackSpec := fmt.Sprintf("%s:%s", callbackNamespace, callbackValue) var setOptions *buntdb.SetOptions @@ -998,7 +998,7 @@ func (am *AccountManager) deserializeRawAccount(raw rawClientAccount, cfName str result.Name = raw.Name result.NameCasefolded = cfName regTimeInt, _ := strconv.ParseInt(raw.RegisteredAt, 10, 64) - result.RegisteredAt = time.Unix(regTimeInt, 0).UTC() + result.RegisteredAt = time.Unix(0, regTimeInt).UTC() e := json.Unmarshal([]byte(raw.Credentials), &result.Credentials) if e != nil { am.server.logger.Error("internal", "could not unmarshal credentials", e.Error()) diff --git a/irc/database.go b/irc/database.go index 56068356..bd9bbafc 100644 --- a/irc/database.go +++ b/irc/database.go @@ -9,6 +9,7 @@ import ( "fmt" "log" "os" + "strconv" "strings" "time" @@ -22,7 +23,7 @@ const ( // 'version' of the database schema keySchemaVersion = "db.version" // latest schema of the db - latestDbSchema = "9" + latestDbSchema = "10" ) type SchemaChanger func(*Config, *buntdb.Tx) error @@ -594,6 +595,32 @@ func schemaChangeV8ToV9(config *Config, tx *buntdb.Tx) error { return nil } +// #836: account registration time at nanosecond resolution +// (mostly to simplify testing) +func schemaChangeV9ToV10(config *Config, tx *buntdb.Tx) error { + prefix := "account.registered.time " + var accounts, times []string + tx.AscendGreaterOrEqual("", prefix, func(key, value string) bool { + if !strings.HasPrefix(key, prefix) { + return false + } + account := strings.TrimPrefix(key, prefix) + accounts = append(accounts, account) + times = append(times, value) + return true + }) + for i, account := range accounts { + time, err := strconv.ParseInt(times[i], 10, 64) + if err != nil { + log.Printf("corrupt registration time entry for %s: %v\n", account, err) + continue + } + time = time * 1000000000 + tx.Set(prefix+account, strconv.FormatInt(time, 10), nil) + } + return nil +} + func init() { allChanges := []SchemaChange{ { @@ -636,6 +663,11 @@ func init() { TargetVersion: "9", Changer: schemaChangeV8ToV9, }, + { + InitialVersion: "9", + TargetVersion: "10", + Changer: schemaChangeV9ToV10, + }, } // build the index diff --git a/irc/server.go b/irc/server.go index c7007fe6..685e3423 100644 --- a/irc/server.go +++ b/irc/server.go @@ -919,14 +919,16 @@ func (server *Server) GetHistorySequence(providedChannel *Channel, client *Clien if config.History.Restrictions.ExpireTime != 0 { cutoff = time.Now().UTC().Add(-time.Duration(config.History.Restrictions.ExpireTime)) } - if config.History.Restrictions.EnforceRegistrationDate { + // #836: registration date cutoff is always enforced for DMs + if config.History.Restrictions.EnforceRegistrationDate || channel == nil { regCutoff := client.historyCutoff() // take the later of the two cutoffs if regCutoff.After(cutoff) { cutoff = regCutoff } } - if !cutoff.IsZero() { + // #836 again: grace period is never applied to DMs + if !cutoff.IsZero() && channel != nil { cutoff = cutoff.Add(-time.Duration(config.History.Restrictions.GracePeriod)) }