mirror of https://github.com/aria2/aria2
Implement new RPC authorization using --rpc-secret option
parent
30e4077440
commit
7f6987a4b4
|
@ -926,9 +926,9 @@ RPC Options
|
||||||
|
|
||||||
.. option:: --enable-rpc[=true|false]
|
.. option:: --enable-rpc[=true|false]
|
||||||
|
|
||||||
Enable JSON-RPC/XML-RPC server. It is strongly recommended to set username
|
Enable JSON-RPC/XML-RPC server. It is strongly recommended to set
|
||||||
and password using :option:`--rpc-user` and :option:`--rpc-passwd`
|
secret authorization token using :option:`--rpc-secret` option. See
|
||||||
option. See also :option:`--rpc-listen-port` option. Default: ``false``
|
also :option:`--rpc-listen-port` option. Default: ``false``
|
||||||
|
|
||||||
.. option:: --pause[=true|false]
|
.. option:: --pause[=true|false]
|
||||||
|
|
||||||
|
@ -1004,6 +1004,11 @@ RPC Options
|
||||||
:func:`aria2.addTorrent` or :func:`aria2.addMetalink` will not be
|
:func:`aria2.addTorrent` or :func:`aria2.addMetalink` will not be
|
||||||
saved by :option:`--save-session` option. Default: ``false``
|
saved by :option:`--save-session` option. Default: ``false``
|
||||||
|
|
||||||
|
.. option:: --rpc-secret=<TOKEN>
|
||||||
|
|
||||||
|
Set RPC secret authorization token. Read :ref:`rpc_auth` to know
|
||||||
|
how this option value is used.
|
||||||
|
|
||||||
.. option:: --rpc-secure[=true|false]
|
.. option:: --rpc-secure[=true|false]
|
||||||
|
|
||||||
RPC transport will be encrypted by SSL/TLS. The RPC clients must
|
RPC transport will be encrypted by SSL/TLS. The RPC clients must
|
||||||
|
@ -2021,13 +2026,40 @@ GID
|
||||||
<--gid>` option. When querying download by GID, you can specify the
|
<--gid>` option. When querying download by GID, you can specify the
|
||||||
prefix of GID as long as it is a unique prefix among others.
|
prefix of GID as long as it is a unique prefix among others.
|
||||||
|
|
||||||
|
.. _rpc_auth:
|
||||||
|
|
||||||
|
RPC authorization secret token
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
As of 1.18.4, in addition to HTTP basic authorization, aria2 provides
|
||||||
|
RPC method-level authorization. In the future release, HTTP basic
|
||||||
|
authorization will be removed and RPC method-level authorization will
|
||||||
|
become mandatory.
|
||||||
|
|
||||||
|
To use RPC method-level authorization, user has to specify RPC secret
|
||||||
|
authorization token using :option:`--rpc-secret` option. For each RPC
|
||||||
|
method call, the caller has to include the token prefixed with
|
||||||
|
``token:``. If :option:`--rpc-secret` option is not used and first
|
||||||
|
parameter in the RPC method is a String and starts with ``token:``, it
|
||||||
|
is removed from the parameter before being processed.
|
||||||
|
|
||||||
|
For example, if RPC secret authorization token is ``$$secret$$``, to
|
||||||
|
call `aria2.addUri` RPC method would look like this::
|
||||||
|
|
||||||
|
aria2.addUri("token::$$secret$$", ["http://example.org/file"])
|
||||||
|
|
||||||
|
The `system.multicall` RPC method is treated specially. Since XML-RPC
|
||||||
|
specification only allows one array as a paremter for this method, we
|
||||||
|
don't specify token in its call. Instead, each nested method call has
|
||||||
|
to provide token as 1st parameter as described above.
|
||||||
|
|
||||||
Methods
|
Methods
|
||||||
~~~~~~~
|
~~~~~~~
|
||||||
|
|
||||||
All code examples come from Python2.7 interpreter.
|
All code examples come from Python2.7 interpreter.
|
||||||
|
For *secret* parameter, see :ref:`rpc_auth`.
|
||||||
|
|
||||||
|
.. function:: aria2.addUri([secret], uris[, options[, position]])
|
||||||
.. function:: aria2.addUri(uris[, options[, position]])
|
|
||||||
|
|
||||||
This method adds new HTTP(S)/FTP/BitTorrent Magnet URI. *uris* is of
|
This method adds new HTTP(S)/FTP/BitTorrent Magnet URI. *uris* is of
|
||||||
type array and its element is URI which is of type string. For
|
type array and its element is URI which is of type string. For
|
||||||
|
@ -2075,7 +2107,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.addUri(['http://example.org/file'], {}, 0)
|
>>> s.aria2.addUri(['http://example.org/file'], {}, 0)
|
||||||
'ca3d829cee549a4d'
|
'ca3d829cee549a4d'
|
||||||
|
|
||||||
.. function:: aria2.addTorrent(torrent[, uris[, options[, position]]])
|
.. function:: aria2.addTorrent([secret], torrent[, uris[, options[, position]]])
|
||||||
|
|
||||||
This method adds BitTorrent download by uploading ".torrent" file.
|
This method adds BitTorrent download by uploading ".torrent" file.
|
||||||
If you want to add BitTorrent Magnet URI, use :func:`aria2.addUri`
|
If you want to add BitTorrent Magnet URI, use :func:`aria2.addUri`
|
||||||
|
@ -2125,7 +2157,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.addTorrent(xmlrpclib.Binary(open('file.torrent').read()))
|
>>> s.aria2.addTorrent(xmlrpclib.Binary(open('file.torrent').read()))
|
||||||
'2089b05ecca3d829'
|
'2089b05ecca3d829'
|
||||||
|
|
||||||
.. function:: aria2.addMetalink(metalink[, options[, position]])
|
.. function:: aria2.addMetalink([secret], metalink[, options[, position]])
|
||||||
|
|
||||||
This method adds Metalink download by uploading ".metalink" file.
|
This method adds Metalink download by uploading ".metalink" file.
|
||||||
*metalink* is of type base64 which contains Base64-encoded
|
*metalink* is of type base64 which contains Base64-encoded
|
||||||
|
@ -2170,7 +2202,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.addMetalink(xmlrpclib.Binary(open('file.meta4').read()))
|
>>> s.aria2.addMetalink(xmlrpclib.Binary(open('file.meta4').read()))
|
||||||
['2089b05ecca3d829']
|
['2089b05ecca3d829']
|
||||||
|
|
||||||
.. function:: aria2.remove(gid)
|
.. function:: aria2.remove([secret], gid)
|
||||||
|
|
||||||
This method removes the download denoted by *gid*. *gid* is of type
|
This method removes the download denoted by *gid*. *gid* is of type
|
||||||
string. If specified download is in progress, it is stopped at
|
string. If specified download is in progress, it is stopped at
|
||||||
|
@ -2200,14 +2232,14 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.remove('2089b05ecca3d829')
|
>>> s.aria2.remove('2089b05ecca3d829')
|
||||||
'2089b05ecca3d829'
|
'2089b05ecca3d829'
|
||||||
|
|
||||||
.. function:: aria2.forceRemove(gid)
|
.. function:: aria2.forceRemove([secret], gid)
|
||||||
|
|
||||||
This method removes the download denoted by *gid*. This method
|
This method removes the download denoted by *gid*. This method
|
||||||
behaves just like :func:`aria2.remove` except that this method removes
|
behaves just like :func:`aria2.remove` except that this method removes
|
||||||
download without any action which takes time such as contacting
|
download without any action which takes time such as contacting
|
||||||
BitTorrent tracker.
|
BitTorrent tracker.
|
||||||
|
|
||||||
.. function:: aria2.pause(gid)
|
.. function:: aria2.pause([secret], gid)
|
||||||
|
|
||||||
This method pauses the download denoted by *gid*. *gid* is of type
|
This method pauses the download denoted by *gid*. *gid* is of type
|
||||||
string. The status of paused download becomes ``paused``. If the
|
string. The status of paused download becomes ``paused``. If the
|
||||||
|
@ -2216,36 +2248,36 @@ All code examples come from Python2.7 interpreter.
|
||||||
started. To change status to ``waiting``, use :func:`aria2.unpause` method.
|
started. To change status to ``waiting``, use :func:`aria2.unpause` method.
|
||||||
This method returns GID of paused download.
|
This method returns GID of paused download.
|
||||||
|
|
||||||
.. function:: aria2.pauseAll()
|
.. function:: aria2.pauseAll([secret])
|
||||||
|
|
||||||
This method is equal to calling :func:`aria2.pause` for every active/waiting
|
This method is equal to calling :func:`aria2.pause` for every active/waiting
|
||||||
download. This methods returns ``OK`` for success.
|
download. This methods returns ``OK`` for success.
|
||||||
|
|
||||||
.. function:: aria2.forcePause(pid)
|
.. function:: aria2.forcePause([secret], pid)
|
||||||
|
|
||||||
This method pauses the download denoted by *gid*. This method
|
This method pauses the download denoted by *gid*. This method
|
||||||
behaves just like :func:`aria2.pause` except that this method pauses
|
behaves just like :func:`aria2.pause` except that this method pauses
|
||||||
download without any action which takes time such as contacting
|
download without any action which takes time such as contacting
|
||||||
BitTorrent tracker.
|
BitTorrent tracker.
|
||||||
|
|
||||||
.. function:: aria2.forcePauseAll()
|
.. function:: aria2.forcePauseAll([secret])
|
||||||
|
|
||||||
This method is equal to calling :func:`aria2.forcePause` for every
|
This method is equal to calling :func:`aria2.forcePause` for every
|
||||||
active/waiting download. This methods returns ``OK`` for success.
|
active/waiting download. This methods returns ``OK`` for success.
|
||||||
|
|
||||||
.. function:: aria2.unpause(gid)
|
.. function:: aria2.unpause([secret], gid)
|
||||||
|
|
||||||
This method changes the status of the download denoted by *gid* from
|
This method changes the status of the download denoted by *gid* from
|
||||||
``paused`` to ``waiting``. This makes the download eligible to restart.
|
``paused`` to ``waiting``. This makes the download eligible to restart.
|
||||||
*gid* is of type string. This method returns GID of unpaused
|
*gid* is of type string. This method returns GID of unpaused
|
||||||
download.
|
download.
|
||||||
|
|
||||||
.. function:: aria2.unpauseAll()
|
.. function:: aria2.unpauseAll([secret])
|
||||||
|
|
||||||
This method is equal to calling :func:`aria2.unpause` for every active/waiting
|
This method is equal to calling :func:`aria2.unpause` for every active/waiting
|
||||||
download. This methods returns ``OK`` for success.
|
download. This methods returns ``OK`` for success.
|
||||||
|
|
||||||
.. function:: aria2.tellStatus(gid[, keys])
|
.. function:: aria2.tellStatus([secret], gid[, keys])
|
||||||
|
|
||||||
This method returns download progress of the download denoted by
|
This method returns download progress of the download denoted by
|
||||||
*gid*. *gid* is of type string. *keys* is array of string. If it is
|
*gid*. *gid* is of type string. *keys* is array of string. If it is
|
||||||
|
@ -2443,7 +2475,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> pprint(r)
|
>>> pprint(r)
|
||||||
{'completedLength': '34896138', 'gid': '2089b05ecca3d829', 'totalLength': '34896138'}
|
{'completedLength': '34896138', 'gid': '2089b05ecca3d829', 'totalLength': '34896138'}
|
||||||
|
|
||||||
.. function:: aria2.getUris(gid)
|
.. function:: aria2.getUris([secret], gid)
|
||||||
|
|
||||||
This method returns URIs used in the download denoted by *gid*. *gid*
|
This method returns URIs used in the download denoted by *gid*. *gid*
|
||||||
is of type string. The response is of type array and its element is of
|
is of type string. The response is of type array and its element is of
|
||||||
|
@ -2481,7 +2513,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> pprint(r)
|
>>> pprint(r)
|
||||||
[{'status': 'used', 'uri': 'http://example.org/file'}]
|
[{'status': 'used', 'uri': 'http://example.org/file'}]
|
||||||
|
|
||||||
.. function:: aria2.getFiles(gid)
|
.. function:: aria2.getFiles([secret], gid)
|
||||||
|
|
||||||
This method returns file list of the download denoted by *gid*. *gid*
|
This method returns file list of the download denoted by *gid*. *gid*
|
||||||
is of type string. The response is of type array and its element is of
|
is of type string. The response is of type array and its element is of
|
||||||
|
@ -2553,7 +2585,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
'uris': [{'status': 'used',
|
'uris': [{'status': 'used',
|
||||||
'uri': 'http://example.org/file'}]}]
|
'uri': 'http://example.org/file'}]}]
|
||||||
|
|
||||||
.. function:: aria2.getPeers(gid)
|
.. function:: aria2.getPeers([secret], gid)
|
||||||
|
|
||||||
This method returns peer list of the download denoted by *gid*. *gid*
|
This method returns peer list of the download denoted by *gid*. *gid*
|
||||||
is of type string. This method is for BitTorrent only. The response
|
is of type string. This method is for BitTorrent only. The response
|
||||||
|
@ -2648,7 +2680,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
'seeder': 'false,
|
'seeder': 'false,
|
||||||
'uploadSpeed': '6890'}]
|
'uploadSpeed': '6890'}]
|
||||||
|
|
||||||
.. function:: aria2.getServers(gid)
|
.. function:: aria2.getServers([secret], gid)
|
||||||
|
|
||||||
This method returns currently connected HTTP(S)/FTP servers of the download denoted by *gid*. *gid* is of type string. The response
|
This method returns currently connected HTTP(S)/FTP servers of the download denoted by *gid*. *gid* is of type string. The response
|
||||||
is of type array and its element is of type struct and it contains
|
is of type array and its element is of type struct and it contains
|
||||||
|
@ -2701,14 +2733,14 @@ All code examples come from Python2.7 interpreter.
|
||||||
'downloadSpeed': '20285',
|
'downloadSpeed': '20285',
|
||||||
'uri': 'http://example.org/file'}]}]
|
'uri': 'http://example.org/file'}]}]
|
||||||
|
|
||||||
.. function:: aria2.tellActive([keys])
|
.. function:: aria2.tellActive([secret], [keys])
|
||||||
|
|
||||||
This method returns the list of active downloads. The response is of
|
This method returns the list of active downloads. The response is of
|
||||||
type array and its element is the same struct returned by
|
type array and its element is the same struct returned by
|
||||||
:func:`aria2.tellStatus` method. For *keys* parameter, please refer to
|
:func:`aria2.tellStatus` method. For *keys* parameter, please refer to
|
||||||
:func:`aria2.tellStatus` method.
|
:func:`aria2.tellStatus` method.
|
||||||
|
|
||||||
.. function:: aria2.tellWaiting(offset, num, [keys])
|
.. function:: aria2.tellWaiting([secret], offset, num, [keys])
|
||||||
|
|
||||||
This method returns the list of waiting download, including paused
|
This method returns the list of waiting download, including paused
|
||||||
downloads. *offset* is of type integer and specifies the offset from
|
downloads. *offset* is of type integer and specifies the offset from
|
||||||
|
@ -2732,7 +2764,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
The response is of type array and its element is the same struct
|
The response is of type array and its element is the same struct
|
||||||
returned by :func:`aria2.tellStatus` method.
|
returned by :func:`aria2.tellStatus` method.
|
||||||
|
|
||||||
.. function:: aria2.tellStopped(offset, num, [keys])
|
.. function:: aria2.tellStopped([secret], offset, num, [keys])
|
||||||
|
|
||||||
This method returns the list of stopped download. *offset* is of type
|
This method returns the list of stopped download. *offset* is of type
|
||||||
integer and specifies the offset from the oldest download. *num* is of
|
integer and specifies the offset from the oldest download. *num* is of
|
||||||
|
@ -2745,7 +2777,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
The response is of type array and its element is the same struct
|
The response is of type array and its element is the same struct
|
||||||
returned by :func:`aria2.tellStatus` method.
|
returned by :func:`aria2.tellStatus` method.
|
||||||
|
|
||||||
.. function:: aria2.changePosition(gid, pos, how)
|
.. function:: aria2.changePosition([secret], gid, pos, how)
|
||||||
|
|
||||||
This method changes the position of the download denoted by
|
This method changes the position of the download denoted by
|
||||||
*gid*. *pos* is of type integer. *how* is of type string. If *how* is
|
*gid*. *pos* is of type integer. *how* is of type string. If *how* is
|
||||||
|
@ -2789,7 +2821,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.changePosition('2089b05ecca3d829', 0, 'POS_SET')
|
>>> s.aria2.changePosition('2089b05ecca3d829', 0, 'POS_SET')
|
||||||
0
|
0
|
||||||
|
|
||||||
.. function:: aria2.changeUri(gid, fileIndex, delUris, addUris[, position])
|
.. function:: aria2.changeUri([secret], gid, fileIndex, delUris, addUris[, position])
|
||||||
|
|
||||||
This method removes URIs in *delUris* from and appends URIs in
|
This method removes URIs in *delUris* from and appends URIs in
|
||||||
*addUris* to download denoted by *gid*. *delUris* and *addUris* are
|
*addUris* to download denoted by *gid*. *delUris* and *addUris* are
|
||||||
|
@ -2837,7 +2869,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
['http://example.org/file'])
|
['http://example.org/file'])
|
||||||
[0, 1]
|
[0, 1]
|
||||||
|
|
||||||
.. function:: aria2.getOption(gid)
|
.. function:: aria2.getOption([secret], gid)
|
||||||
|
|
||||||
This method returns options of the download denoted by *gid*. The
|
This method returns options of the download denoted by *gid*. The
|
||||||
response is of type struct. Its key is the name of option. The value
|
response is of type struct. Its key is the name of option. The value
|
||||||
|
@ -2882,7 +2914,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
'async-dns': 'true',
|
'async-dns': 'true',
|
||||||
....
|
....
|
||||||
|
|
||||||
.. function:: aria2.changeOption(gid, options)
|
.. function:: aria2.changeOption([secret], gid, options)
|
||||||
|
|
||||||
This method changes options of the download denoted by *gid*
|
This method changes options of the download denoted by *gid*
|
||||||
dynamically. *gid* is of type string. *options* is of type struct.
|
dynamically. *gid* is of type string. *options* is of type struct.
|
||||||
|
@ -2933,7 +2965,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.changeOption('2089b05ecca3d829', {'max-download-limit':'20K'})
|
>>> s.aria2.changeOption('2089b05ecca3d829', {'max-download-limit':'20K'})
|
||||||
'OK'
|
'OK'
|
||||||
|
|
||||||
.. function:: aria2.getGlobalOption()
|
.. function:: aria2.getGlobalOption([secret])
|
||||||
|
|
||||||
This method returns global options. The response is of type
|
This method returns global options. The response is of type
|
||||||
struct. Its key is the name of option. The value type is string.
|
struct. Its key is the name of option. The value type is string.
|
||||||
|
@ -2943,7 +2975,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
for the options of newly added download, the response contains keys
|
for the options of newly added download, the response contains keys
|
||||||
returned by :func:`aria2.getOption` method.
|
returned by :func:`aria2.getOption` method.
|
||||||
|
|
||||||
.. function:: aria2.changeGlobalOption(options)
|
.. function:: aria2.changeGlobalOption([secret], options)
|
||||||
|
|
||||||
This method changes global options dynamically. *options* is of type
|
This method changes global options dynamically. *options* is of type
|
||||||
struct.
|
struct.
|
||||||
|
@ -2974,7 +3006,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
value. Note that log file is always opened in append mode. This method
|
value. Note that log file is always opened in append mode. This method
|
||||||
returns ``OK`` for success.
|
returns ``OK`` for success.
|
||||||
|
|
||||||
.. function:: aria2.getGlobalStat()
|
.. function:: aria2.getGlobalStat([secret])
|
||||||
|
|
||||||
This method returns global statistics such as overall download and
|
This method returns global statistics such as overall download and
|
||||||
upload speed. The response is of type struct and contains following
|
upload speed. The response is of type struct and contains following
|
||||||
|
@ -3026,12 +3058,12 @@ All code examples come from Python2.7 interpreter.
|
||||||
'numWaiting': '0',
|
'numWaiting': '0',
|
||||||
'uploadSpeed': '0'}
|
'uploadSpeed': '0'}
|
||||||
|
|
||||||
.. function:: aria2.purgeDownloadResult()
|
.. function:: aria2.purgeDownloadResult([secret])
|
||||||
|
|
||||||
This method purges completed/error/removed downloads to free memory.
|
This method purges completed/error/removed downloads to free memory.
|
||||||
This method returns ``OK``.
|
This method returns ``OK``.
|
||||||
|
|
||||||
.. function:: aria2.removeDownloadResult(gid)
|
.. function:: aria2.removeDownloadResult([secret], gid)
|
||||||
|
|
||||||
This method removes completed/error/removed download denoted by *gid*
|
This method removes completed/error/removed download denoted by *gid*
|
||||||
from memory. This method returns ``OK`` for success.
|
from memory. This method returns ``OK`` for success.
|
||||||
|
@ -3061,7 +3093,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.removeDownloadResult('2089b05ecca3d829')
|
>>> s.aria2.removeDownloadResult('2089b05ecca3d829')
|
||||||
'OK'
|
'OK'
|
||||||
|
|
||||||
.. function:: aria2.getVersion()
|
.. function:: aria2.getVersion([secret])
|
||||||
|
|
||||||
This method returns version of the program and the list of enabled
|
This method returns version of the program and the list of enabled
|
||||||
features. The response is of type struct and contains following keys.
|
features. The response is of type struct and contains following keys.
|
||||||
|
@ -3111,7 +3143,7 @@ All code examples come from Python2.7 interpreter.
|
||||||
'XML-RPC'],
|
'XML-RPC'],
|
||||||
'version': '1.11.0'}
|
'version': '1.11.0'}
|
||||||
|
|
||||||
.. function:: aria2.getSessionInfo()
|
.. function:: aria2.getSessionInfo([secret])
|
||||||
|
|
||||||
This method returns session information.
|
This method returns session information.
|
||||||
The response is of type struct and contains following key.
|
The response is of type struct and contains following key.
|
||||||
|
@ -3140,11 +3172,11 @@ All code examples come from Python2.7 interpreter.
|
||||||
>>> s.aria2.getSessionInfo()
|
>>> s.aria2.getSessionInfo()
|
||||||
{'sessionId': 'cd6a3bc6a1de28eb5bfa181e5f6b916d44af31a9'}
|
{'sessionId': 'cd6a3bc6a1de28eb5bfa181e5f6b916d44af31a9'}
|
||||||
|
|
||||||
.. function:: aria2.shutdown()
|
.. function:: aria2.shutdown([secret])
|
||||||
|
|
||||||
This method shutdowns aria2. This method returns ``OK``.
|
This method shutdowns aria2. This method returns ``OK``.
|
||||||
|
|
||||||
.. function:: aria2.forceShutdown()
|
.. function:: aria2.forceShutdown([secret])
|
||||||
|
|
||||||
This method shutdowns :func:`aria2. This method behaves like aria2.shutdown`
|
This method shutdowns :func:`aria2. This method behaves like aria2.shutdown`
|
||||||
except that any actions which takes time such as contacting BitTorrent
|
except that any actions which takes time such as contacting BitTorrent
|
||||||
|
|
|
@ -239,6 +239,8 @@ OptionParser.new do |opt|
|
||||||
opt.on("--user USERNAME", "XML-RPC username"){|val| options["user"]=val }
|
opt.on("--user USERNAME", "XML-RPC username"){|val| options["user"]=val }
|
||||||
opt.on("--passwd PASSWORD", "XML-RPC password"){|val| options["passwd"]=val }
|
opt.on("--passwd PASSWORD", "XML-RPC password"){|val| options["passwd"]=val }
|
||||||
|
|
||||||
|
opt.on("--secret SECRET", "XML-RPC secret authorization token"){|val| options["secret"]=val }
|
||||||
|
|
||||||
opt.banner=<<EOS
|
opt.banner=<<EOS
|
||||||
Usage: #{program_name} addUri URI... [options]
|
Usage: #{program_name} addUri URI... [options]
|
||||||
#{program_name} addTorrent /path/to/torrent_file URI... [options]
|
#{program_name} addTorrent /path/to/torrent_file URI... [options]
|
||||||
|
@ -300,6 +302,7 @@ end
|
||||||
if not options.has_key?("port") then
|
if not options.has_key?("port") then
|
||||||
options["port"]="6800"
|
options["port"]="6800"
|
||||||
end
|
end
|
||||||
|
secret = if options.has_key?("secret") then "token:"+options["secret"] else nil end
|
||||||
|
|
||||||
client=XMLRPC::Client.new3({:host => options["server"],
|
client=XMLRPC::Client.new3({:host => options["server"],
|
||||||
:port => options["port"],
|
:port => options["port"],
|
||||||
|
@ -311,79 +314,89 @@ options.delete("server")
|
||||||
options.delete("port")
|
options.delete("port")
|
||||||
options.delete("user")
|
options.delete("user")
|
||||||
options.delete("passwd")
|
options.delete("passwd")
|
||||||
|
options.delete("secret")
|
||||||
|
|
||||||
|
def client_call client, secret, method, *params
|
||||||
|
if secret.nil?
|
||||||
|
client.call(method, *params)
|
||||||
|
else
|
||||||
|
client.call(method, secret, *params)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if command == "addUri" then
|
if command == "addUri" then
|
||||||
result=client.call("aria2."+command, resources, options)
|
result=client_call(client, secret, "aria2."+command, resources, options)
|
||||||
elsif command == "addTorrent" then
|
elsif command == "addTorrent" then
|
||||||
torrentData=IO.read(resources[0])
|
torrentData=IO.read(resources[0])
|
||||||
result=client.call("aria2."+command,
|
result=client_call(client, secret, "aria2."+command,
|
||||||
XMLRPC::Base64.new(torrentData), resources[1..-1], options)
|
XMLRPC::Base64.new(torrentData), resources[1..-1], options)
|
||||||
elsif command == "addMetalink" then
|
elsif command == "addMetalink" then
|
||||||
metalinkData=IO.read(resources[0])
|
metalinkData=IO.read(resources[0])
|
||||||
result=client.call("aria2."+command,
|
result=client_call(client, secret, "aria2."+command,
|
||||||
XMLRPC::Base64.new(metalinkData), options)
|
XMLRPC::Base64.new(metalinkData), options)
|
||||||
elsif command == "tellStatus" then
|
elsif command == "tellStatus" then
|
||||||
result=client.call("aria2."+command, resources[0], resources[1..-1])
|
result=client_call(client, secret, "aria2."+command,
|
||||||
|
resources[0], resources[1..-1])
|
||||||
elsif command == "tellActive" then
|
elsif command == "tellActive" then
|
||||||
result=client.call("aria2."+command, resources[0..-1])
|
result=client_call(client, secret, "aria2."+command, resources[0..-1])
|
||||||
elsif command == "tellWaiting" then
|
elsif command == "tellWaiting" then
|
||||||
result=client.call("aria2."+command, resources[0].to_i(), resources[1].to_i(),
|
result=client_call(client, secret, "aria2."+command, resources[0].to_i(),
|
||||||
resources[2..-1])
|
resources[1].to_i(), resources[2..-1])
|
||||||
elsif command == "tellStopped" then
|
elsif command == "tellStopped" then
|
||||||
result=client.call("aria2."+command, resources[0].to_i(), resources[1].to_i(),
|
result=client_call(client, secret, "aria2."+command, resources[0].to_i(),
|
||||||
resources[2..-1])
|
resources[1].to_i(), resources[2..-1])
|
||||||
elsif command == "getOption" then
|
elsif command == "getOption" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "getGlobalOption" then
|
elsif command == "getGlobalOption" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "pause" then
|
elsif command == "pause" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "pauseAll" then
|
elsif command == "pauseAll" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "forcePause" then
|
elsif command == "forcePause" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "forcePauseAll" then
|
elsif command == "forcePauseAll" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "unpause" then
|
elsif command == "unpause" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "unpauseAll" then
|
elsif command == "unpauseAll" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "remove" then
|
elsif command == "remove" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "forceRemove" then
|
elsif command == "forceRemove" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "changePosition" then
|
elsif command == "changePosition" then
|
||||||
result=client.call("aria2."+command, resources[0], resources[1].to_i(),
|
result=client_call(client, secret, "aria2."+command, resources[0],
|
||||||
resources[2])
|
resources[1].to_i(), resources[2])
|
||||||
elsif command == "getFiles" then
|
elsif command == "getFiles" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "getUris" then
|
elsif command == "getUris" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "getPeers" then
|
elsif command == "getPeers" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "getServers" then
|
elsif command == "getServers" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "purgeDownloadResult" then
|
elsif command == "purgeDownloadResult" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "removeDownloadResult" then
|
elsif command == "removeDownloadResult" then
|
||||||
result=client.call("aria2."+command, resources[0])
|
result=client_call(client, secret, "aria2."+command, resources[0])
|
||||||
elsif command == "changeOption" then
|
elsif command == "changeOption" then
|
||||||
result=client.call("aria2."+command, resources[0], options)
|
result=client_call(client, secret, "aria2."+command, resources[0], options)
|
||||||
elsif command == "changeGlobalOption" then
|
elsif command == "changeGlobalOption" then
|
||||||
result=client.call("aria2."+command, options)
|
result=client_call(client, secret, "aria2."+command, options)
|
||||||
elsif command == "getVersion" then
|
elsif command == "getVersion" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "getSessionInfo" then
|
elsif command == "getSessionInfo" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "shutdown" then
|
elsif command == "shutdown" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "forceShutdown" then
|
elsif command == "forceShutdown" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "getGlobalStat" then
|
elsif command == "getGlobalStat" then
|
||||||
result=client.call("aria2."+command)
|
result=client_call(client, secret, "aria2."+command)
|
||||||
elsif command == "appendUri" then
|
elsif command == "appendUri" then
|
||||||
result=client.call("aria2.changeUri", resources[0], resources[1].to_i(), [],
|
result=client_call(client, secret, "aria2.changeUri", resources[0],
|
||||||
resources[2..-1])
|
resources[1].to_i(), [], resources[2..-1])
|
||||||
else
|
else
|
||||||
puts "Command not recognized"
|
puts "Command not recognized"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
@ -865,6 +865,14 @@ std::vector<OptionHandler*> OptionHandlerFactory::createOptionHandlers()
|
||||||
op->setChangeGlobalOption(true);
|
op->setChangeGlobalOption(true);
|
||||||
handlers.push_back(op);
|
handlers.push_back(op);
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
OptionHandler* op(new DefaultOptionHandler
|
||||||
|
(PREF_RPC_SECRET,
|
||||||
|
TEXT_RPC_SECRET));
|
||||||
|
op->addTag(TAG_RPC);
|
||||||
|
op->setEraseAfterParse(true);
|
||||||
|
handlers.push_back(op);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
OptionHandler* op(new BooleanOptionHandler
|
OptionHandler* op(new BooleanOptionHandler
|
||||||
(PREF_RPC_SECURE,
|
(PREF_RPC_SECURE,
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
#include "fmt.h"
|
#include "fmt.h"
|
||||||
#include "DlAbortEx.h"
|
#include "DlAbortEx.h"
|
||||||
#include "a2functional.h"
|
#include "a2functional.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -68,9 +69,33 @@ std::unique_ptr<ValueBase> RpcMethod::createErrorResponse
|
||||||
return std::move(params);
|
return std::move(params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RpcMethod::authorize(RpcRequest& req, DownloadEngine* e)
|
||||||
|
{
|
||||||
|
std::string token;
|
||||||
|
// We always treat first parameter as token if it is string and
|
||||||
|
// starts with "token:" and remove it from parameter list, so that
|
||||||
|
// we don't have to add conditionals to all RPCMethod
|
||||||
|
// implementations.
|
||||||
|
if(req.params && !req.params->empty()) {
|
||||||
|
auto t = downcast<String>(req.params->get(0));
|
||||||
|
if(t) {
|
||||||
|
if(util::startsWith(t->s(), "token:")) {
|
||||||
|
token = t->s().substr(6);
|
||||||
|
req.params->pop_front();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(e && e->getOption()->defined(PREF_RPC_SECRET)) {
|
||||||
|
if(token != e->getOption()->get(PREF_RPC_SECRET)) {
|
||||||
|
throw DL_ABORT_EX("Unauthorized");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RpcResponse RpcMethod::execute(RpcRequest req, DownloadEngine* e)
|
RpcResponse RpcMethod::execute(RpcRequest req, DownloadEngine* e)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
authorize(req, e);
|
||||||
auto r = process(req, e);
|
auto r = process(req, e);
|
||||||
return RpcResponse(0, std::move(r), std::move(req.id));
|
return RpcResponse(0, std::move(r), std::move(req.id));
|
||||||
} catch(RecoverableException& ex) {
|
} catch(RecoverableException& ex) {
|
||||||
|
|
|
@ -93,6 +93,8 @@ public:
|
||||||
|
|
||||||
virtual ~RpcMethod();
|
virtual ~RpcMethod();
|
||||||
|
|
||||||
|
virtual void authorize(RpcRequest& req, DownloadEngine* e);
|
||||||
|
|
||||||
// Do work to fulfill RpcRequest req and returns its result as
|
// Do work to fulfill RpcRequest req and returns its result as
|
||||||
// RpcResponse. This method delegates to process() method.
|
// RpcResponse. This method delegates to process() method.
|
||||||
RpcResponse execute(RpcRequest req, DownloadEngine* e);
|
RpcResponse execute(RpcRequest req, DownloadEngine* e);
|
||||||
|
|
|
@ -572,6 +572,14 @@ protected:
|
||||||
virtual std::unique_ptr<ValueBase> process
|
virtual std::unique_ptr<ValueBase> process
|
||||||
(const RpcRequest& req, DownloadEngine* e) CXX11_OVERRIDE;
|
(const RpcRequest& req, DownloadEngine* e) CXX11_OVERRIDE;
|
||||||
public:
|
public:
|
||||||
|
virtual void authorize(RpcRequest& req, DownloadEngine* e) CXX11_OVERRIDE
|
||||||
|
{
|
||||||
|
// Batch calls (e.g., system.multicall) authorizes only nested
|
||||||
|
// methods. This is because XML-RPC system.multicall only accpets
|
||||||
|
// methods array and there is no room for us to insert token
|
||||||
|
// parameter.
|
||||||
|
}
|
||||||
|
|
||||||
static const char* getMethodName()
|
static const char* getMethodName()
|
||||||
{
|
{
|
||||||
return "system.multicall";
|
return "system.multicall";
|
||||||
|
|
|
@ -151,6 +151,16 @@ void List::set(size_t index, std::unique_ptr<ValueBase> v)
|
||||||
list_[index] = std::move(v);
|
list_[index] = std::move(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void List::pop_front()
|
||||||
|
{
|
||||||
|
list_.pop_front();
|
||||||
|
}
|
||||||
|
|
||||||
|
void List::pop_back()
|
||||||
|
{
|
||||||
|
list_.pop_back();
|
||||||
|
}
|
||||||
|
|
||||||
void List::append(std::unique_ptr<ValueBase> v)
|
void List::append(std::unique_ptr<ValueBase> v)
|
||||||
{
|
{
|
||||||
list_.push_back(std::move(v));
|
list_.push_back(std::move(v));
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ private:
|
||||||
|
|
||||||
class List:public ValueBase {
|
class List:public ValueBase {
|
||||||
public:
|
public:
|
||||||
typedef std::vector<std::unique_ptr<ValueBase>> ValueType;
|
typedef std::deque<std::unique_ptr<ValueBase>> ValueType;
|
||||||
|
|
||||||
List();
|
List();
|
||||||
|
|
||||||
|
@ -196,6 +196,12 @@ public:
|
||||||
// Returns the const reference of the object at the given index.
|
// Returns the const reference of the object at the given index.
|
||||||
ValueBase* operator[](size_t index) const;
|
ValueBase* operator[](size_t index) const;
|
||||||
|
|
||||||
|
// Pops the value in the front of the list.
|
||||||
|
void pop_front();
|
||||||
|
|
||||||
|
// Pops the value in the back of the list.
|
||||||
|
void pop_back();
|
||||||
|
|
||||||
// Returns a read/write iterator that points to the first object in
|
// Returns a read/write iterator that points to the first object in
|
||||||
// list.
|
// list.
|
||||||
ValueType::iterator begin();
|
ValueType::iterator begin();
|
||||||
|
|
|
@ -359,6 +359,8 @@ PrefPtr PREF_GID = makePref("gid");
|
||||||
// values: 1*digit
|
// values: 1*digit
|
||||||
PrefPtr PREF_SAVE_SESSION_INTERVAL = makePref("save-session-interval");
|
PrefPtr PREF_SAVE_SESSION_INTERVAL = makePref("save-session-interval");
|
||||||
PrefPtr PREF_ENABLE_COLOR = makePref("enable-color");
|
PrefPtr PREF_ENABLE_COLOR = makePref("enable-color");
|
||||||
|
// value: string
|
||||||
|
PrefPtr PREF_RPC_SECRET = makePref("rpc-secret");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FTP related preferences
|
* FTP related preferences
|
||||||
|
|
|
@ -296,6 +296,8 @@ extern PrefPtr PREF_GID;
|
||||||
extern PrefPtr PREF_SAVE_SESSION_INTERVAL;
|
extern PrefPtr PREF_SAVE_SESSION_INTERVAL;
|
||||||
// value: true |false
|
// value: true |false
|
||||||
extern PrefPtr PREF_ENABLE_COLOR;
|
extern PrefPtr PREF_ENABLE_COLOR;
|
||||||
|
// value: string
|
||||||
|
extern PrefPtr PREF_RPC_SECRET;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FTP related preferences
|
* FTP related preferences
|
||||||
|
|
|
@ -770,11 +770,11 @@
|
||||||
" option is useful when the system does not have\n" \
|
" option is useful when the system does not have\n" \
|
||||||
" /etc/resolv.conf and user does not have the\n" \
|
" /etc/resolv.conf and user does not have the\n" \
|
||||||
" permission to create it.")
|
" permission to create it.")
|
||||||
#define TEXT_ENABLE_RPC \
|
#define TEXT_ENABLE_RPC \
|
||||||
_(" --enable-rpc[=true|false] Enable JSON-RPC/XML-RPC server.\n" \
|
_(" --enable-rpc[=true|false] Enable JSON-RPC/XML-RPC server.\n" \
|
||||||
" It is strongly recommended to set username and\n" \
|
" It is strongly recommended to set secret\n" \
|
||||||
" password using --rpc-user and --rpc-passwd\n" \
|
" authorization token using --rpc-secret option.\n" \
|
||||||
" option. See also --rpc-listen-port option.")
|
" See also --rpc-listen-port option.")
|
||||||
#define TEXT_RPC_MAX_REQUEST_SIZE \
|
#define TEXT_RPC_MAX_REQUEST_SIZE \
|
||||||
_(" --rpc-max-request-size=SIZE Set max size of JSON-RPC/XML-RPC request. If aria2\n" \
|
_(" --rpc-max-request-size=SIZE Set max size of JSON-RPC/XML-RPC request. If aria2\n" \
|
||||||
" detects the request is more than SIZE bytes, it\n" \
|
" detects the request is more than SIZE bytes, it\n" \
|
||||||
|
@ -960,3 +960,5 @@
|
||||||
" when aria2 exits.")
|
" when aria2 exits.")
|
||||||
#define TEXT_ENABLE_COLOR \
|
#define TEXT_ENABLE_COLOR \
|
||||||
_(" --enable-color[=true|false] Enable color output for a terminal.")
|
_(" --enable-color[=true|false] Enable color output for a terminal.")
|
||||||
|
#define TEXT_RPC_SECRET \
|
||||||
|
_(" --rpc-secret=TOKEN Set RPC secret authorization token.")
|
||||||
|
|
|
@ -33,6 +33,7 @@ namespace rpc {
|
||||||
class RpcMethodTest:public CppUnit::TestFixture {
|
class RpcMethodTest:public CppUnit::TestFixture {
|
||||||
|
|
||||||
CPPUNIT_TEST_SUITE(RpcMethodTest);
|
CPPUNIT_TEST_SUITE(RpcMethodTest);
|
||||||
|
CPPUNIT_TEST(testAuthorize);
|
||||||
CPPUNIT_TEST(testAddUri);
|
CPPUNIT_TEST(testAddUri);
|
||||||
CPPUNIT_TEST(testAddUri_withoutUri);
|
CPPUNIT_TEST(testAddUri_withoutUri);
|
||||||
CPPUNIT_TEST(testAddUri_notUri);
|
CPPUNIT_TEST(testAddUri_notUri);
|
||||||
|
@ -96,6 +97,7 @@ public:
|
||||||
(std::vector<std::shared_ptr<RequestGroup>>{}, 1, option_.get()));
|
(std::vector<std::shared_ptr<RequestGroup>>{}, 1, option_.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testAuthorize();
|
||||||
void testAddUri();
|
void testAddUri();
|
||||||
void testAddUri_withoutUri();
|
void testAddUri_withoutUri();
|
||||||
void testAddUri_notUri();
|
void testAddUri_notUri();
|
||||||
|
@ -159,6 +161,47 @@ RpcRequest createReq(std::string methodName)
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
void RpcMethodTest::testAuthorize()
|
||||||
|
{
|
||||||
|
// Select RPC method which takes non-string parameter to make sure
|
||||||
|
// that token: prefixed parameter is stripped before the call.
|
||||||
|
TellActiveRpcMethod m;
|
||||||
|
// no secret token set and no token: prefixed parameter is given
|
||||||
|
{
|
||||||
|
auto req = createReq(TellActiveRpcMethod::getMethodName());
|
||||||
|
auto res = m.execute(std::move(req), e_.get());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(0, res.code);
|
||||||
|
}
|
||||||
|
// no secret token set and token: prefixed parameter is given
|
||||||
|
{
|
||||||
|
auto req = createReq(GetVersionRpcMethod::getMethodName());
|
||||||
|
req.params->append("token:foo");
|
||||||
|
auto res = m.execute(std::move(req), e_.get());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(0, res.code);
|
||||||
|
}
|
||||||
|
e_->getOption()->put(PREF_RPC_SECRET, "foo");
|
||||||
|
// secret token set and no token: prefixed parameter is given
|
||||||
|
{
|
||||||
|
auto req = createReq(GetVersionRpcMethod::getMethodName());
|
||||||
|
auto res = m.execute(std::move(req), e_.get());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(1, res.code);
|
||||||
|
}
|
||||||
|
// secret token set and token: prefixed parameter is given
|
||||||
|
{
|
||||||
|
auto req = createReq(GetVersionRpcMethod::getMethodName());
|
||||||
|
req.params->append("token:foo");
|
||||||
|
auto res = m.execute(std::move(req), e_.get());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(0, res.code);
|
||||||
|
}
|
||||||
|
// secret token set and bad token: prefixed parameter is given
|
||||||
|
{
|
||||||
|
auto req = createReq(GetVersionRpcMethod::getMethodName());
|
||||||
|
req.params->append("token:foo2");
|
||||||
|
auto res = m.execute(std::move(req), e_.get());
|
||||||
|
CPPUNIT_ASSERT_EQUAL(1, res.code);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void RpcMethodTest::testAddUri()
|
void RpcMethodTest::testAddUri()
|
||||||
{
|
{
|
||||||
AddUriRpcMethod m;
|
AddUriRpcMethod m;
|
||||||
|
|
Loading…
Reference in New Issue