mirror of
https://github.com/anope/anope.git
synced 2026-06-12 17:24:49 +02:00
Add the rpc_user module.
This commit is contained in:
@@ -906,6 +906,29 @@ module
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rpc_user
|
||||||
|
*
|
||||||
|
* Adds support for the following RPC methods:
|
||||||
|
*
|
||||||
|
* anope.checkCredentials anope.identify
|
||||||
|
* anope.listCommands anope.command
|
||||||
|
*
|
||||||
|
* Requires either the jsonrpc or xmlrpc module.
|
||||||
|
*
|
||||||
|
* See docs/RPC/rpc_user.md for API documentation.
|
||||||
|
*/
|
||||||
|
#module
|
||||||
|
{
|
||||||
|
name = "rpc_user"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Some commands can only be executed by a real IRC user. You can work around
|
||||||
|
* this executing them as an IRC user logged into the account if one exists.
|
||||||
|
*/
|
||||||
|
pretenduser = no
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rpc_data
|
* rpc_data
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -206,6 +206,58 @@ class AnopeRPC {
|
|||||||
messageUser(source, target, ...messages) {
|
messageUser(source, target, ...messages) {
|
||||||
return this.run("anope.messageUser", source, target, ...messages);
|
return this.run("anope.messageUser", source, target, ...messages);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the specified credentials are valid.
|
||||||
|
*
|
||||||
|
* Requires the rpc_user module to be loaded.
|
||||||
|
*
|
||||||
|
* @param {string} account A nickname belonging to the account to check.
|
||||||
|
* @param {string} password The password for the specified account.
|
||||||
|
* @returns {object} An object containing basic information about the account.
|
||||||
|
*/
|
||||||
|
checkCredentials(account, password) {
|
||||||
|
return this.run("anope.checkCredentials", account, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies an IRC user to the specified account.
|
||||||
|
*
|
||||||
|
* Requires the rpc_user module to be loaded.
|
||||||
|
*
|
||||||
|
* @param {string} account Either an account identifier or nickname belonging to the account to
|
||||||
|
* identify to.
|
||||||
|
* @param {string} password The nickname of the IRC user to identify to the account.
|
||||||
|
*/
|
||||||
|
identify(account, user) {
|
||||||
|
return this.run("anope.identify", account, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all commands that exist on the network.
|
||||||
|
*
|
||||||
|
* Requires the rpc_user module to be loaded.
|
||||||
|
*
|
||||||
|
* @param {...*} services The nicknames of the services to list commands for.
|
||||||
|
* @returns {object} An object containing information about the available commands.
|
||||||
|
*/
|
||||||
|
listCommands(...services) {
|
||||||
|
return this.run("anope.listCommands", ...services);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all commands that exist on the network.
|
||||||
|
*
|
||||||
|
* Requires the rpc_user module to be loaded.
|
||||||
|
*
|
||||||
|
* @param {string} account If non-empty then the account to execute the command as.
|
||||||
|
* @param {string} service The service which the command exists on.
|
||||||
|
* @param {...*} command The the command to execute and any parameters to pass to it.
|
||||||
|
* @returns {object} An object containing information about the available commands.
|
||||||
|
*/
|
||||||
|
command(account, service, ...command) {
|
||||||
|
return this.run("anope.command", account, service, ...command);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -186,6 +186,50 @@ class AnopeRPC
|
|||||||
def message_user(source, target, *messages)
|
def message_user(source, target, *messages)
|
||||||
self.run("anope.messageUser", source, target, *messages)
|
self.run("anope.messageUser", source, target, *messages)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Checks whether the specified credentials are valid.
|
||||||
|
#
|
||||||
|
# Requires the rpc_user module to be loaded.
|
||||||
|
#
|
||||||
|
# @param account [String] A nickname belonging to the account to check.
|
||||||
|
# @param password [String] The password for the specified account.
|
||||||
|
# @return [Hash] A hash containing basic information about the account.
|
||||||
|
def check_credentials(account, password)
|
||||||
|
self.run("anope.checkCredentials", account, password)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Identifies an IRC user to the specified account.
|
||||||
|
#
|
||||||
|
# Requires the rpc_user module to be loaded.
|
||||||
|
#
|
||||||
|
# @param account [String] Either an account identifier or nickname belonging to the account to
|
||||||
|
# identify to.
|
||||||
|
# @param password [String] The nickname of the IRC user to identify to the account.
|
||||||
|
def identify(account, user)
|
||||||
|
self.run("anope.identify", account, user)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Lists all commands that exist on the network.
|
||||||
|
#
|
||||||
|
# Requires the rpc_user module to be loaded.
|
||||||
|
#
|
||||||
|
# @param services [Array<String>] The nicknames of the services to list commands for.
|
||||||
|
# @return [Hash] A hash containing information about the available commands.
|
||||||
|
def list_commands(*services)
|
||||||
|
self.run("anope.listCommands", *services)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Lists all commands that exist on the network.
|
||||||
|
#
|
||||||
|
# Requires the rpc_user module to be loaded.
|
||||||
|
#
|
||||||
|
# @param account [String] If non-empty then the account to execute the command as.
|
||||||
|
# @param service [String] The service which the command exists on.
|
||||||
|
# @param command [Array<String>] The the command to execute and any parameters to pass to it.
|
||||||
|
# @return [Hash] A hash containing information about the available commands.
|
||||||
|
def command(account, service, *command)
|
||||||
|
self.run("anope.command", account, service, *command)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
=begin
|
||||||
|
|||||||
@@ -0,0 +1,175 @@
|
|||||||
|
# Anope `rpc_user` RPC interface
|
||||||
|
|
||||||
|
## `anope.checkCredentials`
|
||||||
|
|
||||||
|
Checks whether the specified credentials are valid.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Index | Description
|
||||||
|
----- | -----------
|
||||||
|
0 | A nickname belonging to the account to check.
|
||||||
|
1 | The password for the specified account.
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
Code | Description
|
||||||
|
------ | -----------
|
||||||
|
-32099 | The specified account does not exist.
|
||||||
|
-32098 | The specified password is not correct.
|
||||||
|
-32097 | The specified account is suspended.
|
||||||
|
|
||||||
|
### Result
|
||||||
|
|
||||||
|
Returns a map containing basic information about the account. More information about the account can be found by calling [the `anope.account` event using the value from the `uniqueid` field (requires the rpc_data module)](./rpc_user.md).
|
||||||
|
|
||||||
|
Key | Type | Description
|
||||||
|
--- | ---- | -----------
|
||||||
|
account | string | The display nickname of the account.
|
||||||
|
confirmed | boolean | Whether the account has been confirmed.
|
||||||
|
uniqueid | uint | The unique immutable identifier of the account.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"account": "foo",
|
||||||
|
"confirmed": true,
|
||||||
|
"uniqueid": 11085415958920757000,
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `anope.identify`
|
||||||
|
|
||||||
|
Identifies an IRC user to the specified account.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Index | Description
|
||||||
|
----- | -----------
|
||||||
|
0 | Either an account identifier or nickname belonging to the account to identify to.
|
||||||
|
1 | The nickname of the IRC user to identify to the account.
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
Code | Description
|
||||||
|
------ | -----------
|
||||||
|
-32099 | The specified account does not exist.
|
||||||
|
-32098 | The specified IRC user does not exist.
|
||||||
|
|
||||||
|
### Result
|
||||||
|
|
||||||
|
This procedure returns no result.
|
||||||
|
|
||||||
|
## `anope.listCommands`
|
||||||
|
|
||||||
|
Lists all commands that exist on the network.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Index | Description
|
||||||
|
----- | -----------
|
||||||
|
0...n | The nicknames of the services to list commands for. If none are specified then all commands are returned.
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
Code | Description
|
||||||
|
------ | -----------
|
||||||
|
-32098 | The specified service does not exist.
|
||||||
|
|
||||||
|
### Result
|
||||||
|
|
||||||
|
Returns a map containing information about the available commands.
|
||||||
|
|
||||||
|
Key | Type | Description
|
||||||
|
--- | ---- | -----------
|
||||||
|
\* | map | A key-value map of services to the commands that exist on them.
|
||||||
|
\*.\* | string | A key-value map of commands to information about the commands.
|
||||||
|
\*.\*.group | string or null | The group that the command belongs to or null if the command is not grouped.
|
||||||
|
\*.\*.hidden | boolean | Whether the command is visible in the help output.
|
||||||
|
\*.\*.maxparams | uint or null | The maximum number of parameters that the command accepts or null if there is no limit.
|
||||||
|
\*.\*.minparams | uint | The minimum number of parameters that the command accepts.
|
||||||
|
\*.\*.permission | string or null | The services operator permission required to execute the command or null if no permissions are required.
|
||||||
|
\*.\*.requiresaccount | boolean | Whether a caller must be logged into an account to execute the command.
|
||||||
|
\*.\*.requiresuser | boolean | Whether an IRC user is required to execute the command.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Global": {
|
||||||
|
"GLOBAL": {
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"maxparams": 1,
|
||||||
|
"minparams": 0,
|
||||||
|
"permission": "global/global",
|
||||||
|
"requiresaccount": true,
|
||||||
|
"requiresuser": false
|
||||||
|
},
|
||||||
|
"HELP": {
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"maxparams": null,
|
||||||
|
"minparams": 0,
|
||||||
|
"permission": null,
|
||||||
|
"requireaccount": false,
|
||||||
|
"requireuser": false
|
||||||
|
},
|
||||||
|
"QUEUE": {
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"maxparams": 2,
|
||||||
|
"minparams": 1,
|
||||||
|
"permission": "global/queue",
|
||||||
|
"requireaccount": true,
|
||||||
|
"requireuser": false
|
||||||
|
},
|
||||||
|
"SERVER": {
|
||||||
|
"group": null,
|
||||||
|
"hidden": false,
|
||||||
|
"maxparams": 2,
|
||||||
|
"minparams": 1,
|
||||||
|
"permission": "global/server",
|
||||||
|
"requireaccount": true,
|
||||||
|
"requireuser": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## `anope.commands`
|
||||||
|
|
||||||
|
Executes the specified command.
|
||||||
|
|
||||||
|
### Parameters
|
||||||
|
|
||||||
|
Index | Description
|
||||||
|
----- | -----------
|
||||||
|
0 | If non-empty then the account to execute the command as.
|
||||||
|
1 | The service which the command exists on.
|
||||||
|
2...n | The the command to execute and any parameters to pass to it.
|
||||||
|
|
||||||
|
### Errors
|
||||||
|
|
||||||
|
Code | Description
|
||||||
|
------ | -----------
|
||||||
|
-32099 | The specified account does not exist.
|
||||||
|
-32098 | The specified service does not exist.
|
||||||
|
-32097 | The specified command does not exist.
|
||||||
|
|
||||||
|
### Result
|
||||||
|
|
||||||
|
Returns an array of messages returned by the command.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"Global commands:",
|
||||||
|
" GLOBAL Send a message to all users",
|
||||||
|
" HELP Displays this list and give information about commands",
|
||||||
|
" QUEUE Manages your pending message queue.",
|
||||||
|
" SERVER Send a message to all users on a server"
|
||||||
|
]
|
||||||
|
```
|
||||||
@@ -0,0 +1,335 @@
|
|||||||
|
/*
|
||||||
|
*
|
||||||
|
* (C) 2010-2025 Anope Team
|
||||||
|
* Contact us at team@anope.org
|
||||||
|
*
|
||||||
|
* Please read COPYING and README for further details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "module.h"
|
||||||
|
#include "modules/rpc.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
// Used by anope.checkCredentials, anope.identify, and anope.command.
|
||||||
|
ERR_INVALID_ACCOUNT = RPC::ERR_CUSTOM_START,
|
||||||
|
|
||||||
|
// Used by anope.checkCredentials
|
||||||
|
ERR_INVALID_PASSWORD = RPC::ERR_CUSTOM_START + 1,
|
||||||
|
ERR_ACCOUNT_SUSPENDED = RPC::ERR_CUSTOM_START + 2,
|
||||||
|
|
||||||
|
// Used by anope.identify
|
||||||
|
ERR_INVALID_USER = RPC::ERR_CUSTOM_START + 1,
|
||||||
|
|
||||||
|
// Used by anope.listCommands, and anope.command
|
||||||
|
ERR_INVALID_SERVICE = RPC::ERR_CUSTOM_START + 1,
|
||||||
|
|
||||||
|
// Used by anope.command
|
||||||
|
ERR_INVALID_COMMAND = RPC::ERR_CUSTOM_START + 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class AnopeCheckCredentialsRPCEvent final
|
||||||
|
: public RPC::Event
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
class RPCIdentifyRequest final
|
||||||
|
: public IdentifyRequest
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
RPC::Request request;
|
||||||
|
Reference<HTTP::Client> client;
|
||||||
|
Reference<RPC::ServiceInterface> rpcinterface;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RPCIdentifyRequest(Module *m, RPC::Request &r, HTTP::Client *c, RPC::ServiceInterface *i, const Anope::string &a, const Anope::string &p)
|
||||||
|
: IdentifyRequest(m, a, p, c->GetIP())
|
||||||
|
, request(r)
|
||||||
|
, client(c)
|
||||||
|
, rpcinterface(i)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnSuccess() override
|
||||||
|
{
|
||||||
|
if (!rpcinterface || !client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto *na = NickAlias::Find(GetAccount());
|
||||||
|
if (!na)
|
||||||
|
return; // Should never happen.
|
||||||
|
|
||||||
|
if (na->nc->HasExt("NS_SUSPENDED"))
|
||||||
|
{
|
||||||
|
request.Error(ERR_ACCOUNT_SUSPENDED, "Account suspended");
|
||||||
|
rpcinterface->Reply(request);
|
||||||
|
client->SendReply(&request.reply);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &root = request.Root();
|
||||||
|
root.Reply("account", na->nc->display)
|
||||||
|
.Reply("confirmed", !na->nc->HasExt("UNCONFIRMED"))
|
||||||
|
.Reply("uniqueid", na->nc->GetId());
|
||||||
|
|
||||||
|
rpcinterface->Reply(request);
|
||||||
|
client->SendReply(&request.reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnFail() override
|
||||||
|
{
|
||||||
|
if (!rpcinterface || !client)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (NickAlias::Find(GetAccount()))
|
||||||
|
request.Error(ERR_INVALID_ACCOUNT, "Invalid account");
|
||||||
|
else
|
||||||
|
request.Error(ERR_INVALID_PASSWORD, "Invalid password");
|
||||||
|
|
||||||
|
rpcinterface->Reply(request);
|
||||||
|
client->SendReply(&request.reply);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
AnopeCheckCredentialsRPCEvent(Module *o)
|
||||||
|
: RPC::Event(o, "anope.checkCredentials", 2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Run(RPC::ServiceInterface *iface, HTTP::Client *client, RPC::Request &request) override
|
||||||
|
{
|
||||||
|
const auto &username = request.data[0];
|
||||||
|
const auto &password = request.data[1];
|
||||||
|
if (username.empty() || password.empty())
|
||||||
|
{
|
||||||
|
request.Error(RPC::ERR_INVALID_PARAMS, "Not enough parameters");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *req = new RPCIdentifyRequest(this->owner, request, client, iface, username, password);
|
||||||
|
FOREACH_MOD(OnCheckAuthentication, (nullptr, req));
|
||||||
|
req->Dispatch();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnopeIdentifyRPCEvent final
|
||||||
|
: public RPC::Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AnopeIdentifyRPCEvent(Module *o)
|
||||||
|
: RPC::Event(o, "anope.identify", 2)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Run(RPC::ServiceInterface *iface, HTTP::Client *client, RPC::Request &request) override
|
||||||
|
{
|
||||||
|
auto *na = request.data[0].is_pos_number_only()
|
||||||
|
? NickAlias::FindId(Anope::Convert(request.data[0], 0))
|
||||||
|
: NickAlias::Find(request.data[0]);
|
||||||
|
if (!na)
|
||||||
|
{
|
||||||
|
request.Error(ERR_INVALID_ACCOUNT, "No such account");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *u = User::Find(request.data[1]);
|
||||||
|
if (!u)
|
||||||
|
{
|
||||||
|
request.Error(ERR_INVALID_USER, "No such user");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
u->Identify(na);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnopeListCommandsRPCEvent final
|
||||||
|
: public RPC::Event
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AnopeListCommandsRPCEvent(Module *o)
|
||||||
|
: RPC::Event(o, "anope.listCommands")
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Run(RPC::ServiceInterface *iface, HTTP::Client *client, RPC::Request &request) override
|
||||||
|
{
|
||||||
|
std::vector<BotInfo *> bots;
|
||||||
|
if (request.data.empty())
|
||||||
|
{
|
||||||
|
for (const auto &[_, bi] : *BotListByNick)
|
||||||
|
bots.push_back(bi);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (const auto &bot : request.data)
|
||||||
|
{
|
||||||
|
auto *bi = BotInfo::Find(bot);
|
||||||
|
if (!bi)
|
||||||
|
{
|
||||||
|
request.Error(ERR_INVALID_SERVICE, "No such service");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
bots.push_back(bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto &root = request.Root();
|
||||||
|
for (const auto *bi : bots)
|
||||||
|
{
|
||||||
|
if (bi->commands.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto &commands = root.ReplyMap(bi->nick);
|
||||||
|
for (const auto &[command, info] : bi->commands)
|
||||||
|
{
|
||||||
|
ServiceReference<Command> cmdref("Command", info.name);
|
||||||
|
if (!cmdref)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
auto &cmdinfo = commands.ReplyMap(command);
|
||||||
|
cmdinfo.Reply("hidden", info.hide)
|
||||||
|
.Reply("minparams", cmdref->min_params)
|
||||||
|
.Reply("requiresaccount", !cmdref->AllowUnregistered())
|
||||||
|
.Reply("requiresuser", cmdref->RequireUser());
|
||||||
|
|
||||||
|
if (info.group.empty())
|
||||||
|
cmdinfo.Reply("group", nullptr);
|
||||||
|
else
|
||||||
|
cmdinfo.Reply("group", info.group);
|
||||||
|
|
||||||
|
if (cmdref->max_params)
|
||||||
|
cmdinfo.Reply("maxparams", cmdref->max_params);
|
||||||
|
else
|
||||||
|
cmdinfo.Reply("maxparams", nullptr);
|
||||||
|
|
||||||
|
if (info.permission.empty())
|
||||||
|
cmdinfo.Reply("permission", nullptr);
|
||||||
|
else
|
||||||
|
cmdinfo.Reply("permission", info.permission);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class AnopeCommandRPCEvent final
|
||||||
|
: public RPC::Event
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
class RPCCommandReply final
|
||||||
|
: public CommandReply
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
RPC::Array &root;
|
||||||
|
|
||||||
|
public:
|
||||||
|
RPCCommandReply(RPC::Array &r)
|
||||||
|
: root(r)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SendMessage(BotInfo *source, const Anope::string &msg) override
|
||||||
|
{
|
||||||
|
root.Reply(NormalizeBuffer(msg.replace_all_cs("\x1A", "\x20")));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static bool pretenduser;
|
||||||
|
|
||||||
|
AnopeCommandRPCEvent(Module *o)
|
||||||
|
: RPC::Event(o, "anope.command", 3)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Run(RPC::ServiceInterface *iface, HTTP::Client *client, RPC::Request &request) override
|
||||||
|
{
|
||||||
|
NickAlias *na = nullptr;
|
||||||
|
if (!request.data[0].empty())
|
||||||
|
{
|
||||||
|
na = request.data[0].is_pos_number_only()
|
||||||
|
? NickAlias::FindId(Anope::Convert(request.data[0], 0))
|
||||||
|
: NickAlias::Find(request.data[0]);
|
||||||
|
if (!na)
|
||||||
|
{
|
||||||
|
request.Error(ERR_INVALID_ACCOUNT, "No such account");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *bi = BotInfo::Find(request.data[1], true);
|
||||||
|
if (!bi)
|
||||||
|
{
|
||||||
|
request.Error(ERR_INVALID_SERVICE, "No such service");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Anope::string command;
|
||||||
|
for (size_t i = 2; i < request.data.size(); ++i)
|
||||||
|
{
|
||||||
|
if (!command.empty())
|
||||||
|
command.push_back(' ');
|
||||||
|
command.append(request.data[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
User *u = nullptr;
|
||||||
|
if (pretenduser && na && !na->nc->users.empty())
|
||||||
|
{
|
||||||
|
// Try and find the nick user first.
|
||||||
|
for (auto *user : na->nc->users)
|
||||||
|
{
|
||||||
|
if (user->nick.equals_ci(na->nick))
|
||||||
|
{
|
||||||
|
u = user;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No nick user, fallback to the first.
|
||||||
|
if (!u)
|
||||||
|
u = na->nc->users.front();
|
||||||
|
}
|
||||||
|
|
||||||
|
RPCCommandReply reply(request.Root<RPC::Array>());
|
||||||
|
CommandSource source(na ? na->nick : "RPC", u, na ? *na->nc : nullptr, &reply, bi, request.id);
|
||||||
|
|
||||||
|
if (!Command::Run(source, command))
|
||||||
|
request.Error(ERR_INVALID_COMMAND, "No such command");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
bool AnopeCommandRPCEvent::pretenduser = false;
|
||||||
|
|
||||||
|
class ModuleRPCAccount final
|
||||||
|
: public Module
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
AnopeCheckCredentialsRPCEvent anopecheckcredentialsrpcevent;
|
||||||
|
AnopeIdentifyRPCEvent anopeidentifyrpcevent;
|
||||||
|
AnopeListCommandsRPCEvent anopelistcommandsrpcevent;
|
||||||
|
AnopeCommandRPCEvent anopecommandrpcevent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModuleRPCAccount(const Anope::string &modname, const Anope::string &creator)
|
||||||
|
: Module(modname, creator, EXTRA | VENDOR)
|
||||||
|
, anopecheckcredentialsrpcevent(this)
|
||||||
|
, anopeidentifyrpcevent(this)
|
||||||
|
, anopelistcommandsrpcevent(this)
|
||||||
|
, anopecommandrpcevent(this)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnReload(Configuration::Conf &conf) override
|
||||||
|
{
|
||||||
|
AnopeCommandRPCEvent::pretenduser = conf.GetModule(this).Get<bool>("pretenduser");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
MODULE_INIT(ModuleRPCAccount)
|
||||||
Reference in New Issue
Block a user