Skip to content

Commit

Permalink
clients: add ignore list to idle user autounsub
Browse files Browse the repository at this point in the history
This list includes well-known bots, to prevent them from being
erroneously removed by default.
  • Loading branch information
miki authored and miki-totefu committed Sep 26, 2023
1 parent 5eb0c02 commit 8f4b7f5
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 12 deletions.
5 changes: 3 additions & 2 deletions brclient/appstate.go
Expand Up @@ -3174,8 +3174,9 @@ func newAppState(sendMsg func(tea.Msg), lndLogLines *sloglinesbuffer.Buffer,
ResourcesProvider: resRouter,
NoLoadChatHistory: args.NoLoadChatHistory,

AutoHandshakeInterval: args.AutoHandshakeInterval,
AutoRemoveIdleUsersInterval: args.AutoRemoveIdleUsersInterval,
AutoHandshakeInterval: args.AutoHandshakeInterval,
AutoRemoveIdleUsersInterval: args.AutoRemoveIdleUsersInterval,
AutoRemoveIdleUsersIgnoreList: args.AutoRemoveIdleUsersIgnore,

CertConfirmer: func(ctx context.Context, cs *tls.ConnectionState,
svrID *zkidentity.PublicIdentity) error {
Expand Down
7 changes: 7 additions & 0 deletions brclient/brclient.conf.go
Expand Up @@ -66,6 +66,13 @@ root = {{ .Root }}
# Set to zero to disable idle user removal.
# autoremoveidleusersinterval = 60d
# Comma-separated list of users to NOT auto-unsubscribe or remove from GCs
# during the idle check. This may be either the nick or UID of the user. By
# default, some well-known bots are included in this list:
# 86abd31f2141b274196d481edd061a00ab7a56b61a31656775c8a590d612b966 - Oprah
# ad716557157c1f191d8b5f8c6757ea41af49de27dc619fc87f337ca85be325ee - GC bot
# autoremoveignorelist =
# logging and debug
[log]
Expand Down
18 changes: 18 additions & 0 deletions brclient/config.go
Expand Up @@ -30,6 +30,16 @@ const (
appName = "brclient"
)

var (
// defaultAutoRemoveIgnoreList is the list of users that should not be
// removed during the auto unsubscribe idle check. By default, these are
// some well-known bots.
defaultAutoRemoveIgnoreList = strings.Join([]string{
"86abd31f2141b274196d481edd061a00ab7a56b61a31656775c8a590d612b966", // Oprah
"ad716557157c1f191d8b5f8c6757ea41af49de27dc619fc87f337ca85be325ee", // GC bot
}, ",")
)

var (
// Error to signal loadConfig() completed everything the cmd had to do
// and main() should exit.
Expand Down Expand Up @@ -99,6 +109,7 @@ type config struct {

AutoHandshakeInterval time.Duration
AutoRemoveIdleUsersInterval time.Duration
AutoRemoveIdleUsersIgnore []string

SyncFreeList bool

Expand Down Expand Up @@ -274,6 +285,7 @@ func loadConfig() (*config, error) {

flagAutoHandshake := fs.String("autohandshakeinterval", "21d", "")
flagAutoRemove := fs.String("autoremoveidleusersinterval", "60d", "")
flagAutoRemoveIgnoreList := fs.String("autoremoveignorelist", defaultAutoRemoveIgnoreList, "")

// log
flagMsgRoot := fs.String("log.msglog", defaultMsgRoot, "Root for message log files")
Expand Down Expand Up @@ -410,6 +422,11 @@ func loadConfig() (*config, error) {
mimeMap[spl[0]] = spl[1]
}

autoRemoveIgnoreList := strings.Split(*flagAutoRemoveIgnoreList, ",")
for i := range autoRemoveIgnoreList {
autoRemoveIgnoreList[i] = strings.TrimSpace(autoRemoveIgnoreList[i])
}

var jrpcListen []string
if *flagJSONRPCListen != "" {
jrpcListen = strings.Split(*flagJSONRPCListen, ",")
Expand Down Expand Up @@ -502,6 +519,7 @@ func loadConfig() (*config, error) {

AutoHandshakeInterval: autoHandshakeInterval,
AutoRemoveIdleUsersInterval: autoRemoveInterval,
AutoRemoveIdleUsersIgnore: autoRemoveIgnoreList,

SyncFreeList: *flagSyncFreeList,
ExtenalEditorForComments: *flagExternalEditorForComments,
Expand Down
19 changes: 18 additions & 1 deletion bruig/flutterui/bruig/lib/config.dart
Expand Up @@ -7,6 +7,11 @@ import 'package:path/path.dart' as path;

const APPNAME = "bruig";

const defaultAutoRemoveIgnoreList = [
"86abd31f2141b274196d481edd061a00ab7a56b61a31656775c8a590d612b966", // Oprah
"ad716557157c1f191d8b5f8c6757ea41af49de27dc619fc87f337ca85be325ee", // GC bot
];

String homeDir() {
var env = Platform.environment;
if (Platform.isWindows) {
Expand Down Expand Up @@ -83,6 +88,7 @@ class Config {
late final bool syncFreeList;
late final int autoHandshakeInterval;
late final int autoRemoveIdleUsersInterval;
late final List<String> autoRemoveIgnoreList;

Config();
Config.filled(
Expand Down Expand Up @@ -111,7 +117,8 @@ class Config {
this.noLoadChatHistory: true,
this.syncFreeList: true,
this.autoHandshakeInterval: 21 * 24 * 60 * 60,
this.autoRemoveIdleUsersInterval: 60 * 24 * 60 * 60});
this.autoRemoveIdleUsersInterval: 60 * 24 * 60 * 60,
this.autoRemoveIgnoreList: defaultAutoRemoveIgnoreList});
factory Config.newWithRPCHost(
Config cfg, String rpcHost, String tlsCert, String macaroonPath) =>
Config.filled(
Expand Down Expand Up @@ -141,6 +148,7 @@ class Config {
syncFreeList: cfg.syncFreeList,
autoHandshakeInterval: cfg.autoHandshakeInterval,
autoRemoveIdleUsersInterval: cfg.autoRemoveIdleUsersInterval,
autoRemoveIgnoreList: cfg.autoRemoveIgnoreList,
);

Future<void> saveConfig(String filepath) async {
Expand Down Expand Up @@ -200,6 +208,13 @@ Future<Config> loadConfig(String filepath) async {
return v != null && v != "" ? int.tryParse(v) : null;
};

var getCommaList = (String section, String opt) {
var v = f.get(section, opt);
return v != null && v != ""
? v.split(",").map((e) => e.trim()).toList()
: null;
};

var iniLogFile = f.get("log", "logfile");
String logfile = path.join(appDataDir, "applogs", "${APPNAME}.log");
if (iniLogFile != null) {
Expand Down Expand Up @@ -255,6 +270,8 @@ Future<Config> loadConfig(String filepath) async {
parseDurationSeconds(f.get("default", "autohandshakeinterval") ?? "21d");
c.autoRemoveIdleUsersInterval = parseDurationSeconds(
f.get("default", "autoremoveidleusersinterval") ?? "60d");
c.autoRemoveIgnoreList = getCommaList("default", "autoremoveignorelist") ??
defaultAutoRemoveIgnoreList;

if (c.walletType != "disabled") {
c.lnRPCHost = f.get("payment", "lnrpchost") ?? "localhost:10009";
Expand Down
3 changes: 2 additions & 1 deletion bruig/flutterui/bruig/lib/main.dart
Expand Up @@ -167,7 +167,8 @@ class _AppState extends State<App> with WindowListener {
cfg.circuitLimit,
cfg.noLoadChatHistory,
cfg.autoHandshakeInterval,
cfg.autoRemoveIdleUsersInterval);
cfg.autoRemoveIdleUsersInterval,
cfg.autoRemoveIgnoreList);
await Golib.initClient(initArgs);

navkey.currentState!.pushReplacementNamed(OverviewScreen.routeName);
Expand Down
5 changes: 4 additions & 1 deletion bruig/flutterui/plugin/lib/definitions.dart
Expand Up @@ -59,6 +59,8 @@ class InitClient {
final int autoHandshakeInterval;
@JsonKey(name: 'auto_remove_idle_users_interval')
final int autoRemoveIdleUsersInterval;
@JsonKey(name: 'auto_remove_idle_users_ignore')
final List<String> autoRemoveIdleUsersIgnore;

InitClient(
this.dbRoot,
Expand All @@ -82,7 +84,8 @@ class InitClient {
this.circuitLimit,
this.noLoadChatHistory,
this.autoHandshakeInterval,
this.autoRemoveIdleUsersInterval);
this.autoRemoveIdleUsersInterval,
this.autoRemoveIdleUsersIgnore);

Map<String, dynamic> toJson() => _$InitClientToJson(this);
}
Expand Down
4 changes: 4 additions & 0 deletions bruig/flutterui/plugin/lib/definitions.g.dart

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions bruig/golib/command_handlers.go
Expand Up @@ -390,8 +390,9 @@ func handleInitClient(handle uint32, args initClient) error {
ResourcesProvider: resRouter,
NoLoadChatHistory: args.NoLoadChatHistory,

AutoHandshakeInterval: time.Duration(args.AutoHandshakeInterval) * time.Second,
AutoRemoveIdleUsersInterval: time.Duration(args.AutoRemoveIdleUsersInterval) * time.Second,
AutoHandshakeInterval: time.Duration(args.AutoHandshakeInterval) * time.Second,
AutoRemoveIdleUsersInterval: time.Duration(args.AutoRemoveIdleUsersInterval) * time.Second,
AutoRemoveIdleUsersIgnoreList: args.AutoRemoveIdleUsersIgnore,

CertConfirmer: func(ctx context.Context, cs *tls.ConnectionState,
svrID *zkidentity.PublicIdentity) error {
Expand Down
5 changes: 3 additions & 2 deletions bruig/golib/definitions.go
Expand Up @@ -38,8 +38,9 @@ type initClient struct {
TorIsolation bool `json:"torisolation"`
CircuitLimit uint32 `json:"circuit_limit"`

AutoHandshakeInterval int64 `json:"auto_handshake_interval"`
AutoRemoveIdleUsersInterval int64 `json:"auto_remove_idle_users_interval"`
AutoHandshakeInterval int64 `json:"auto_handshake_interval"`
AutoRemoveIdleUsersInterval int64 `json:"auto_remove_idle_users_interval"`
AutoRemoveIdleUsersIgnore []string `json:"auto_remove_idle_users_ignore"`
}

type iDInit struct {
Expand Down
6 changes: 6 additions & 0 deletions client/client.go
Expand Up @@ -189,6 +189,12 @@ type Config struct {
// automatically removed from GCs the local client admins and will be
// automatically unsubscribed from posts.
AutoRemoveIdleUsersInterval time.Duration

// AutoRemoveIdleUsersIgnoreList is a list of users that should NOT be
// forcibly unsubscribed even if they are idle. The values may be an
// user's nick or the prefix of the string representatation of its nick
// (i.e. anything acceptable as returned by UserByNick()).
AutoRemoveIdleUsersIgnoreList []string
}

// logger creates a logger for the given subsystem in the configured backend.
Expand Down
31 changes: 28 additions & 3 deletions client/client_kx.go
Expand Up @@ -719,8 +719,31 @@ func (c *Client) unsubIdleUsers(limitInterval, lastHandshakeInterval time.Durati
adminGCs = append(adminGCs, &gcs[i])
}

c.log.Debugf("Starting auto unsubscribe of idle users with limitDate %s "+
"and limitHandshakeDate %s", limitDate.Format(time.RFC3339),
limitHandshakeDate.Format(time.RFC3339))

// Build ignore list.
ignoreList := make(map[clientintf.UserID]struct{}, len(c.cfg.AutoRemoveIdleUsersIgnoreList))
for _, nick := range c.cfg.AutoRemoveIdleUsersIgnoreList {
uid, err := c.UIDByNick(nick)
if err == nil {
ignoreList[uid] = struct{}{}
} else {
c.log.Warnf("User %q in list to ignore from auto remove "+
"not found", nick)
}
}

users := c.rul.userList()
for _, uid := range users {
// Do not perform autounsub if this user is in the list to
// ignore unsubbing.
if _, ok := ignoreList[uid]; ok {
c.log.Tracef("Ignoring %s in auto unsubscribe action", uid)
continue
}

ru, err := c.rul.byID(uid)
if err != nil {
continue
Expand Down Expand Up @@ -755,9 +778,11 @@ func (c *Client) unsubIdleUsers(limitInterval, lastHandshakeInterval time.Durati
continue
}

ru.log.Infof("User %s is idle (last received msg time is %s). "+
"Removing from any active subscriptions and GCs.",
strescape.Nick(ru.Nick()), lastDecTime.Format(time.RFC3339))
ru.log.Infof("User %s is idle (last received msg time is %s, "+
"last handshake attempt time is %s). Removing from all "+
"active subscriptions and GCs.",
strescape.Nick(ru.Nick()), lastDecTime.Format(time.RFC3339),
ab.LastHandshakeAttempt.Format(time.RFC3339))
c.ntfns.notifyUnsubscribingIdleRemote(ru, lastDecTime)

// Forcibly make user unsub from posts.
Expand Down

0 comments on commit 8f4b7f5

Please sign in to comment.