Skip to content

Permissions

By default a command is owner-only. You opt into wider access deliberately.

Owner-only is the default

go
func (m *Weather) CommandMetas() map[string]goroku.CommandMeta {
	return map[string]goroku.CommandMeta{
		"weather": {OnlyOwner: true},
	}
}

OnlyOwner is checked on identity alone — it ignores sudo, temporary grants and group masks. Use it for anything that touches your account, files or shell.

Permission masks

For commands others may use, Goroku has a bitmask system. The owner assigns masks at runtime with .security; your module declares nothing unless you want a different default.

ConstantGrants
OWNERThe account owner
SUDOUsers on the sudo list
GROUP_OWNERThe group's creator
GROUP_ADMINAny admin
GROUP_ADMIN_BAN_USERSAdmins with ban rights
GROUP_ADMIN_DEL_MSGSAdmins with delete rights
GROUP_ADMIN_PIN_MSGSAdmins with pin rights
GROUP_ADMIN_ADD_ADMINSAdmins who can promote
GROUP_ADMIN_CHANGE_INFOAdmins who can edit info
GROUP_ADMIN_INVITEAdmins who can invite
GROUP_MEMBERAny group member
PMAnyone in private chat
EVERYONEAnyone, anywhere

They combine:

go
GROUP_ADMIN_BAN_USERS | GROUP_OWNER

EVERYONE means everyone

EVERYONE lets any stranger in any chat run the command against your account. Reach for GROUP_MEMBER or a specific admin right first.

Checking inside a handler

go
func (m *Mod) DangerousCmd(msg *goroku.Message) error {
	sm := m.Client.GetSecurityManager()
	if sm == nil || !sm.IsOwner(msg.SenderID) {
		return msg.Answer(m.T("owner_only", "🚫 <b>Owner only</b>"))
	}
	return m.doIt(msg)
}

Prefer the declarative OnlyOwner — the dispatcher rejects before your code runs, so there is no path where you forget the check.

Writing a module others will install

Someone installing your module gives it their Telegram session and their server. Things worth doing:

  • Default to the narrowest permission. Widen only where the feature needs it.
  • Never log secrets. Mark config fields Secret: true (Configuration).
  • Escape user input before putting it in HTML (Answering).
  • Validate before acting. A user-supplied chat ID or path deserves a check.
  • Do not shell out to user input. If you must run a command, pass arguments as a slice — never build a shell string.
go
// Fine: arguments are separate, no shell involved.
exec.CommandContext(ctx, "ffmpeg", "-i", path, out)

// Not fine: a filename with a quote becomes a shell injection.
exec.CommandContext(ctx, "sh", "-c", "ffmpeg -i "+path)

Remote code

Modules loaded over the network are HTTPS-only, and private, loopback, link-local and CGNAT addresses are refused — the resolved IP is checked, not just the hostname, so DNS tricks do not help.

That protects the transport. It says nothing about whether the code is safe. A native module is arbitrary Go running in your process; read it before you install it.

Released under the GNU AGPL v3 License.