/
api.py
121 lines (102 loc) · 3.69 KB
/
api.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# -*- coding: utf-8 -*-
# rdiffweb, A web interface to rdiff-backup repositories
# Copyright (C) 2012-2021 rdiffweb contributors
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Created on Nov 16, 2017
@author: Patrik Dufresne
"""
# Define the logger
import logging
import cherrypy
from rdiffweb.controller import Controller
from rdiffweb.core.librdiff import RdiffTime
from rdiffweb.core.model import UserObject
try:
import simplejson as json
except ImportError:
import json
logger = logging.getLogger(__name__)
def json_handler(*args, **kwargs):
"""Custom json handle to convert RdiffDate to str."""
value = cherrypy.serving.request._json_inner_handler(*args, **kwargs)
def default(o):
if isinstance(o, RdiffTime):
return str(o)
raise TypeError(repr(o) + " is not JSON serializable")
encode = json.JSONEncoder(default=default, ensure_ascii=False).iterencode
for chunk in encode(value):
yield chunk.encode('utf-8')
def _checkpassword(realm, username, password):
"""
Check basic authentication.
"""
# Validate username
userobj = UserObject.get_user(username)
if userobj is not None:
# Verify if the password matches a token.
if userobj.validate_access_token(password):
return True
# Disable password authentication for MFA
if userobj.mfa == UserObject.ENABLED_MFA:
cherrypy.tools.ratelimit.hit()
return False
# Otherwise validate username password
valid = any(cherrypy.engine.publish('login', username, password))
if not valid:
# When invalid, we need to increase the rate limit.
cherrypy.tools.ratelimit.hit()
return valid
class ApiCurrentUser(Controller):
@cherrypy.expose
def default(self):
u = self.app.currentuser
u.refresh_repos()
return {
"email": u.email,
"username": u.username,
"repos": [
{
# Database fields.
"name": repo_obj.name,
"maxage": repo_obj.maxage,
"keepdays": repo_obj.keepdays,
# Repository fields.
"display_name": repo_obj.display_name,
"last_backup_date": repo_obj.last_backup_date,
"status": repo_obj.status[0],
"encoding": repo_obj.encoding,
}
for repo_obj in u.repo_objs
],
}
@cherrypy.tools.json_out(handler=json_handler)
@cherrypy.config(**{'error_page.default': False})
@cherrypy.tools.auth_basic(realm='rdiffweb', checkpassword=_checkpassword, priority=70)
@cherrypy.tools.auth_form(on=False)
@cherrypy.tools.auth_mfa(on=False)
@cherrypy.tools.i18n(on=False)
@cherrypy.tools.ratelimit(scope='rdiffweb-api', hit=0, priority=69)
@cherrypy.tools.sessions(on=False)
class ApiPage(Controller):
"""
This class provide a restful API to access some of the rdiffweb resources.
"""
currentuser = ApiCurrentUser()
@cherrypy.expose
def index(self):
return {
"version": self.app.version,
}