mirror of
https://github.com/danog/TelegramApiServer.git
synced 2024-11-26 11:54:42 +01:00
Add basic auth support
This commit is contained in:
parent
a2baf2de21
commit
8e93934e75
@ -2,6 +2,7 @@
|
|||||||
# Check for outdated .env files
|
# Check for outdated .env files
|
||||||
VERSION=1
|
VERSION=1
|
||||||
|
|
||||||
|
# See "ports" in docker-compose.yml.
|
||||||
SERVER_ADDRESS=0.0.0.0
|
SERVER_ADDRESS=0.0.0.0
|
||||||
SERVER_PORT=9503
|
SERVER_PORT=9503
|
||||||
|
|
||||||
@ -21,6 +22,10 @@ REQUESTS_BULK_INTERVAL=0.5
|
|||||||
# 2) recreate container `docker-compose up -d`
|
# 2) recreate container `docker-compose up -d`
|
||||||
IP_WHITELIST=127.0.0.1
|
IP_WHITELIST=127.0.0.1
|
||||||
|
|
||||||
|
# Allow requests from any IP with given user and password
|
||||||
|
# Example: {"myusername": "mySuperStrongPassword", "otherName": "otherPassword"}
|
||||||
|
PASSWORDS={}
|
||||||
|
|
||||||
# TELEGRAM CLIENT
|
# TELEGRAM CLIENT
|
||||||
TELEGRAM_API_ID=
|
TELEGRAM_API_ID=
|
||||||
TELEGRAM_API_HASH=
|
TELEGRAM_API_HASH=
|
||||||
|
@ -20,6 +20,10 @@ REQUESTS_BULK_INTERVAL=0.5
|
|||||||
# Leave blanc, to allow requests from all IP (THIS WILL MAKE API UNSECURE!)
|
# Leave blanc, to allow requests from all IP (THIS WILL MAKE API UNSECURE!)
|
||||||
IP_WHITELIST=127.0.0.1
|
IP_WHITELIST=127.0.0.1
|
||||||
|
|
||||||
|
# Allow requests from any IP with given user and password
|
||||||
|
# Example: {"myusername": "mySuperStrongPassword", "otherName": "otherPassword"}
|
||||||
|
PASSWORDS={}
|
||||||
|
|
||||||
# TELEGRAM CLIENT
|
# TELEGRAM CLIENT
|
||||||
TELEGRAM_API_ID=
|
TELEGRAM_API_ID=
|
||||||
TELEGRAM_API_HASH=
|
TELEGRAM_API_HASH=
|
||||||
|
108
README.md
108
README.md
@ -58,64 +58,58 @@ docker compose pull
|
|||||||
docker compose up -d
|
docker compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Security
|
||||||
1. Run server/parser
|
Please be careful with settings, otherwise you can expose your telegram session and lose control.
|
||||||
```
|
Default settings allow to access API only from localhost/127.0.0.1.
|
||||||
usage: php server.php [--help] [-a=|--address=127.0.0.1] [-p=|--port=9503] [-s=|--session=] [-e=|--env=.env] [--docker]
|
|
||||||
|
|
||||||
Options:
|
|
||||||
--help Show this message
|
|
||||||
|
|
||||||
-a --address Server ip (optional) (default: 127.0.0.1)
|
|
||||||
To listen external connections use 0.0.0.0 and fill IP_WHITELIST in .env
|
|
||||||
|
|
||||||
-p --port Server port (optional) (default: 9503)
|
|
||||||
|
|
||||||
-s --session Name for session file (optional)
|
|
||||||
Multiple sessions can be specified: "--session=user --session=bot"
|
|
||||||
|
|
||||||
Each session is stored in `sessions/{$session}.madeline`.
|
|
||||||
Nested folders supported.
|
|
||||||
See README for more examples.
|
|
||||||
|
|
||||||
-e --env .env file name. (default: .env).
|
|
||||||
Helpful when need multiple instances with different settings
|
|
||||||
|
|
||||||
--docker Apply some settings for docker: add docker network to whitelist.
|
|
||||||
|
|
||||||
Also some options can be set in .env file (see .env.example)
|
|
||||||
```
|
|
||||||
1. Access Telegram API with simple GET/POST requests.
|
|
||||||
Regular and application/json POST supported.
|
|
||||||
It's recommended to use http_build_query, when using GET requests.
|
|
||||||
|
|
||||||
**Rules:**
|
|
||||||
* All methods from MadelineProto supported: [Methods List](https://docs.madelineproto.xyz/API_docs/methods/)
|
|
||||||
* Url: `http://%address%:%port%/api[/%session%]/%class%.%method%/?%param%=%val%`
|
|
||||||
* <b>Important: api available only from ip in whitelist.</b>
|
|
||||||
By default it is: `127.0.0.1`
|
|
||||||
You can add a client IP in .env file to `IP_WHITELIST` (separate with a comma)
|
|
||||||
|
|
||||||
In docker version by default api available only from localhost (127.0.0.1).
|
|
||||||
To allow connections from the internet, need to change ports in docker-compose.yml to `9503:9503` and recreate the container: `docker compose up -d`.
|
|
||||||
This is very insecure, because this will open TAS port to anyone from the internet.
|
|
||||||
Only protection is the `IP_WHITELIST`, and there are no warranties that it will secure your accounts.
|
|
||||||
* If method is inside class (messages, contacts and etc.) use '.' to separate class from method:
|
|
||||||
`http://127.0.0.1:9503/api/contacts.getContacts`
|
|
||||||
* If method requires array of values, use any name of array, for example 'data':
|
|
||||||
`?data[peer]=@xtrime&data[message]=Hello!`. Order of parameters does't matter in this case.
|
|
||||||
* If method requires one or multiple separate parameters (not inside array) then pass parameters with any names but **in strict order**:
|
|
||||||
`http://127.0.0.1:9503/api/getInfo/?id=@xtrime` or `http://127.0.0.1:9503/api/getInfo/?abcd=@xtrime` works the same
|
|
||||||
|
|
||||||
**Examples:**
|
.env settings:
|
||||||
* get_info about channel/user: `http://127.0.0.1:9503/api/getInfo/?id=@xtrime`
|
- `IP_WHITELIST` - allow specific IP's to make requests without password.
|
||||||
* get_info about currect account: `http://127.0.0.1:9503/api/getSelf`
|
- `PASSWORDS` - protect your api with basic auth.
|
||||||
* repost: `http://127.0.0.1:9503/api/messages.forwardMessages/?data[from_peer]=@xtrime&data[to_peer]=@xtrime&data[id]=1234`
|
Request with correct username and password overrides IP_WHITELIST.
|
||||||
* get messages from channel/user: `http://127.0.0.1:9503/api/getHistory/?data[peer]=@breakingmash&data[limit]=10`
|
If you specify password, then `IP_WHITELIST` is ignored
|
||||||
* get messages with text in HTML: `http://127.0.0.1:9503/api/getHistoryHtml/?data[peer]=@breakingmash&data[limit]=10`
|
How to make requests with basic auth:
|
||||||
* search: `http://127.0.0.1:9503/api/searchGlobal/?data[q]=Hello%20World&data[limit]=10`
|
```shell
|
||||||
* sendMessage: `http://127.0.0.1:9503/api/sendMessage/?data[peer]=@xtrime&data[message]=Hello!`
|
curl --user 'username:password' "http://127.0.0.1:9503/getSelf"
|
||||||
* copy message from one channel to another (not repost): `http://127.0.0.1:9503/api/copyMessages/?data[from_peer]=@xtrime&data[to_peer]=@xtrime&data[id][0]=1`
|
curl "http://username:password@127.0.0.1:9503/getSelf"
|
||||||
|
```
|
||||||
|
|
||||||
|
docker-compose.yml:
|
||||||
|
- `port` - port forwarding rules from host to docker container.
|
||||||
|
Remove 127.0.0.1 to listen all interfaces and forward all requests to container.
|
||||||
|
Make sure to use IP_WHITELIST and/or PASSWORDS settings to protect your account.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
Access Telegram API with simple GET/POST requests.
|
||||||
|
Regular and application/json POST supported.
|
||||||
|
It's recommended to use http_build_query, when using GET requests.
|
||||||
|
|
||||||
|
**Rules:**
|
||||||
|
* All methods from MadelineProto supported: [Methods List](https://docs.madelineproto.xyz/API_docs/methods/)
|
||||||
|
* Url: `http://%address%:%port%/api[/%session%]/%class%.%method%/?%param%=%val%`
|
||||||
|
* <b>Important: api available only from ip in whitelist.</b>
|
||||||
|
By default it is: `127.0.0.1`
|
||||||
|
You can add a client IP in .env file to `IP_WHITELIST` (separate with a comma)
|
||||||
|
|
||||||
|
In docker version by default api available only from localhost (127.0.0.1).
|
||||||
|
To allow connections from the internet, need to change ports in docker-compose.yml to `9503:9503` and recreate the container: `docker compose up -d`.
|
||||||
|
This is very insecure, because this will open TAS port to anyone from the internet.
|
||||||
|
Only protection is the `IP_WHITELIST`, and there are no warranties that it will secure your accounts.
|
||||||
|
* If method is inside class (messages, contacts and etc.) use '.' to separate class from method:
|
||||||
|
`http://127.0.0.1:9503/api/contacts.getContacts`
|
||||||
|
* If method requires array of values, use any name of array, for example 'data':
|
||||||
|
`?data[peer]=@xtrime&data[message]=Hello!`. Order of parameters does't matter in this case.
|
||||||
|
* If method requires one or multiple separate parameters (not inside array) then pass parameters with any names but **in strict order**:
|
||||||
|
`http://127.0.0.1:9503/api/getInfo/?id=@xtrime` or `http://127.0.0.1:9503/api/getInfo/?abcd=@xtrime` works the same
|
||||||
|
|
||||||
|
**Examples:**
|
||||||
|
* get_info about channel/user: `http://127.0.0.1:9503/api/getInfo/?id=@xtrime`
|
||||||
|
* get_info about currect account: `http://127.0.0.1:9503/api/getSelf`
|
||||||
|
* repost: `http://127.0.0.1:9503/api/messages.forwardMessages/?data[from_peer]=@xtrime&data[to_peer]=@xtrime&data[id]=1234`
|
||||||
|
* get messages from channel/user: `http://127.0.0.1:9503/api/getHistory/?data[peer]=@breakingmash&data[limit]=10`
|
||||||
|
* get messages with text in HTML: `http://127.0.0.1:9503/api/getHistoryHtml/?data[peer]=@breakingmash&data[limit]=10`
|
||||||
|
* search: `http://127.0.0.1:9503/api/searchGlobal/?data[q]=Hello%20World&data[limit]=10`
|
||||||
|
* sendMessage: `http://127.0.0.1:9503/api/sendMessage/?data[peer]=@xtrime&data[message]=Hello!`
|
||||||
|
* copy message from one channel to another (not repost): `http://127.0.0.1:9503/api/copyMessages/?data[from_peer]=@xtrime&data[to_peer]=@xtrime&data[id][0]=1`
|
||||||
|
|
||||||
## Advanced features
|
## Advanced features
|
||||||
### Get events/updates
|
### Get events/updates
|
||||||
|
12
composer.lock
generated
12
composer.lock
generated
@ -476,16 +476,16 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "amphp/http",
|
"name": "amphp/http",
|
||||||
"version": "v2.1.0",
|
"version": "v2.1.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/amphp/http.git",
|
"url": "https://github.com/amphp/http.git",
|
||||||
"reference": "9f3500bef4bb15cf41987f21136539c0a06555a3"
|
"reference": "fe6b4dd50c1e70caf823092398074b5082e1d6da"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/amphp/http/zipball/9f3500bef4bb15cf41987f21136539c0a06555a3",
|
"url": "https://api.github.com/repos/amphp/http/zipball/fe6b4dd50c1e70caf823092398074b5082e1d6da",
|
||||||
"reference": "9f3500bef4bb15cf41987f21136539c0a06555a3",
|
"reference": "fe6b4dd50c1e70caf823092398074b5082e1d6da",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
@ -528,7 +528,7 @@
|
|||||||
"description": "Basic HTTP primitives which can be shared by servers and clients.",
|
"description": "Basic HTTP primitives which can be shared by servers and clients.",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/amphp/http/issues",
|
"issues": "https://github.com/amphp/http/issues",
|
||||||
"source": "https://github.com/amphp/http/tree/v2.1.0"
|
"source": "https://github.com/amphp/http/tree/v2.1.1"
|
||||||
},
|
},
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
@ -536,7 +536,7 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2023-08-22T19:50:46+00:00"
|
"time": "2024-04-03T18:00:53+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "amphp/http-client",
|
"name": "amphp/http-client",
|
||||||
|
@ -64,6 +64,7 @@ $settings = [
|
|||||||
explode(',', (string)getenv('IP_WHITELIST'))
|
explode(',', (string)getenv('IP_WHITELIST'))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
'passwords' => (array)json_decode((string)getenv('PASSWORDS'), true),
|
||||||
'bulk_interval' => (float)getenv('REQUESTS_BULK_INTERVAL')
|
'bulk_interval' => (float)getenv('REQUESTS_BULK_INTERVAL')
|
||||||
],
|
],
|
||||||
'health_check' => [
|
'health_check' => [
|
||||||
|
@ -13,23 +13,43 @@ class Authorization implements Middleware
|
|||||||
{
|
{
|
||||||
private array $ipWhitelist;
|
private array $ipWhitelist;
|
||||||
private int $selfIp;
|
private int $selfIp;
|
||||||
|
/**
|
||||||
|
* @var array<string,string>
|
||||||
|
*/
|
||||||
|
private array $passwords;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
$this->ipWhitelist = (array)Config::getInstance()->get('api.ip_whitelist', []);
|
|
||||||
$this->selfIp = ip2long(getHostByName(php_uname('n')));
|
$this->selfIp = ip2long(getHostByName(php_uname('n')));
|
||||||
|
$this->ipWhitelist = (array)Config::getInstance()->get('api.ip_whitelist', []);
|
||||||
|
$this->passwords = Config::getInstance()->get('api.passwords', []);
|
||||||
|
if (!$this->ipWhitelist && !$this->passwords) {
|
||||||
|
throw new \InvalidArgumentException('API is unprotected! Please specify IP_WHITELIST or PASSWORD in .env.docker');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public function handleRequest(Request $request, RequestHandler $requestHandler): Response
|
public function handleRequest(Request $request, RequestHandler $requestHandler): Response
|
||||||
{
|
{
|
||||||
$host = explode(':', $request->getClient()->getRemoteAddress()->toString())[0];
|
[$host] = explode(':', $request->getClient()->getRemoteAddress()->toString(), 2);
|
||||||
if ($this->isIpAllowed($host)) {
|
|
||||||
$response = $requestHandler->handleRequest($request);
|
if ($this->passwords) {
|
||||||
} else {
|
$header = (string)$request->getHeader('Authorization');
|
||||||
$response = ErrorResponses::get(HttpStatus::FORBIDDEN, 'Your host is not allowed: ' . $host);
|
if ($header) {
|
||||||
|
sscanf($header, "Basic %s", $encodedPassword);
|
||||||
|
[$username, $password] = explode(':', base64_decode($encodedPassword), 2);
|
||||||
|
if (array_key_exists($username, $this->passwords) && $this->passwords[$username] === $password) {
|
||||||
|
return $requestHandler->handleRequest($request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorResponses::get(HttpStatus::UNAUTHORIZED, 'Username or password is incorrect');
|
||||||
}
|
}
|
||||||
|
|
||||||
return $response;
|
if ($this->isIpAllowed($host)) {
|
||||||
|
return $requestHandler->handleRequest($request);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ErrorResponses::get(HttpStatus::UNAUTHORIZED, 'Your host is not allowed: ' . $host);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function isIpAllowed(string $host): bool
|
private function isIpAllowed(string $host): bool
|
||||||
|
Loading…
Reference in New Issue
Block a user