Mercurial > libervia-backend
comparison sat/plugins/plugin_misc_ip.py @ 2624:56f94936df1e
code style reformatting using black
author | Goffi <goffi@goffi.org> |
---|---|
date | Wed, 27 Jun 2018 20:14:46 +0200 |
parents | 26edcf3a30eb |
children | 003b8b4b56a7 |
comparison
equal
deleted
inserted
replaced
2623:49533de4540b | 2624:56f94936df1e |
---|---|
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 # along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 | 19 |
20 from sat.core.i18n import _, D_ | 20 from sat.core.i18n import _, D_ |
21 from sat.core.constants import Const as C | 21 from sat.core.constants import Const as C |
22 from sat.core.log import getLogger | 22 from sat.core.log import getLogger |
23 | |
23 log = getLogger(__name__) | 24 log = getLogger(__name__) |
24 from sat.tools import xml_tools | 25 from sat.tools import xml_tools |
25 from twisted.web import client as webclient | 26 from twisted.web import client as webclient |
26 from twisted.web import error as web_error | 27 from twisted.web import error as web_error |
27 from twisted.internet import defer | 28 from twisted.internet import defer |
32 from zope.interface import implements | 33 from zope.interface import implements |
33 from wokkel import disco, iwokkel | 34 from wokkel import disco, iwokkel |
34 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 35 from twisted.words.protocols.jabber.xmlstream import XMPPHandler |
35 from twisted.words.protocols.jabber.error import StanzaError | 36 from twisted.words.protocols.jabber.error import StanzaError |
36 import urlparse | 37 import urlparse |
38 | |
37 try: | 39 try: |
38 import netifaces | 40 import netifaces |
39 except ImportError: | 41 except ImportError: |
40 log.warning(u"netifaces is not available, it help discovering IPs, you can install it on https://pypi.python.org/pypi/netifaces") | 42 log.warning( |
43 u"netifaces is not available, it help discovering IPs, you can install it on https://pypi.python.org/pypi/netifaces" | |
44 ) | |
41 netifaces = None | 45 netifaces = None |
42 | 46 |
43 | 47 |
44 PLUGIN_INFO = { | 48 PLUGIN_INFO = { |
45 C.PI_NAME: "IP discovery", | 49 C.PI_NAME: "IP discovery", |
48 C.PI_MODES: C.PLUG_MODE_BOTH, | 52 C.PI_MODES: C.PLUG_MODE_BOTH, |
49 C.PI_PROTOCOLS: ["XEP-0279"], | 53 C.PI_PROTOCOLS: ["XEP-0279"], |
50 C.PI_RECOMMENDATIONS: ["NAT-PORT"], | 54 C.PI_RECOMMENDATIONS: ["NAT-PORT"], |
51 C.PI_MAIN: "IPPlugin", | 55 C.PI_MAIN: "IPPlugin", |
52 C.PI_HANDLER: "yes", | 56 C.PI_HANDLER: "yes", |
53 C.PI_DESCRIPTION: _("""This plugin help to discover our external IP address.""") | 57 C.PI_DESCRIPTION: _("""This plugin help to discover our external IP address."""), |
54 } | 58 } |
55 | 59 |
56 # TODO: GET_IP_PAGE should be configurable in sat.conf | 60 # TODO: GET_IP_PAGE should be configurable in sat.conf |
57 GET_IP_PAGE = "http://salut-a-toi.org/whereami/" # This page must only return external IP of the requester | 61 GET_IP_PAGE = ( |
62 "http://salut-a-toi.org/whereami/" | |
63 ) # This page must only return external IP of the requester | |
58 GET_IP_LABEL = D_(u"Allow external get IP") | 64 GET_IP_LABEL = D_(u"Allow external get IP") |
59 GET_IP_CATEGORY = "General" | 65 GET_IP_CATEGORY = "General" |
60 GET_IP_NAME = "allow_get_ip" | 66 GET_IP_NAME = "allow_get_ip" |
61 GET_IP_CONFIRM_TITLE = D_(u"Confirm external site request") | 67 GET_IP_CONFIRM_TITLE = D_(u"Confirm external site request") |
62 GET_IP_CONFIRM = D_(u"""To facilitate data transfer, we need to contact a website. | 68 GET_IP_CONFIRM = D_( |
69 u"""To facilitate data transfer, we need to contact a website. | |
63 A request will be done on {page} | 70 A request will be done on {page} |
64 That means that administrators of {domain} can know that you use "{app_name}" and your IP Address. | 71 That means that administrators of {domain} can know that you use "{app_name}" and your IP Address. |
65 | 72 |
66 IP address is an identifier to locate you on Internet (similar to a phone number). | 73 IP address is an identifier to locate you on Internet (similar to a phone number). |
67 | 74 |
68 Do you agree to do this request ? | 75 Do you agree to do this request ? |
69 """).format( | 76 """ |
70 page = GET_IP_PAGE, | 77 ).format( |
71 domain = urlparse.urlparse(GET_IP_PAGE).netloc, | 78 page=GET_IP_PAGE, domain=urlparse.urlparse(GET_IP_PAGE).netloc, app_name=C.APP_NAME |
72 app_name = C.APP_NAME) | 79 ) |
73 NS_IP_CHECK = "urn:xmpp:sic:1" | 80 NS_IP_CHECK = "urn:xmpp:sic:1" |
74 | 81 |
75 PARAMS = """ | 82 PARAMS = """ |
76 <params> | 83 <params> |
77 <general> | 84 <general> |
78 <category name="{category}"> | 85 <category name="{category}"> |
79 <param name="{name}" label="{label}" type="bool" /> | 86 <param name="{name}" label="{label}" type="bool" /> |
80 </category> | 87 </category> |
81 </general> | 88 </general> |
82 </params> | 89 </params> |
83 """.format(category=GET_IP_CATEGORY, name=GET_IP_NAME, label=GET_IP_LABEL) | 90 """.format( |
91 category=GET_IP_CATEGORY, name=GET_IP_NAME, label=GET_IP_LABEL | |
92 ) | |
84 | 93 |
85 | 94 |
86 class IPPlugin(object): | 95 class IPPlugin(object): |
87 # TODO: refresh IP if a new connection is detected | 96 # TODO: refresh IP if a new connection is detected |
88 # TODO: manage IPv6 when implemented in SàT | 97 # TODO: manage IPv6 when implemented in SàT |
92 self.host = host | 101 self.host = host |
93 host.memory.updateParams(PARAMS) | 102 host.memory.updateParams(PARAMS) |
94 | 103 |
95 # NAT-Port | 104 # NAT-Port |
96 try: | 105 try: |
97 self._nat = host.plugins['NAT-PORT'] | 106 self._nat = host.plugins["NAT-PORT"] |
98 except KeyError: | 107 except KeyError: |
99 log.debug(u"NAT port plugin not available") | 108 log.debug(u"NAT port plugin not available") |
100 self._nat = None | 109 self._nat = None |
101 | 110 |
102 # XXX: cache is kept until SàT is restarted | 111 # XXX: cache is kept until SàT is restarted |
116 """Return value of parameter with autorisation of user to do external requests | 125 """Return value of parameter with autorisation of user to do external requests |
117 | 126 |
118 if parameter is not set, a dialog is shown to use to get its confirmation, and parameted is set according to answer | 127 if parameter is not set, a dialog is shown to use to get its confirmation, and parameted is set according to answer |
119 @return (defer.Deferred[bool]): True if external request is autorised | 128 @return (defer.Deferred[bool]): True if external request is autorised |
120 """ | 129 """ |
121 allow_get_ip = self.host.memory.params.getParamA(GET_IP_NAME, GET_IP_CATEGORY, use_default=False) | 130 allow_get_ip = self.host.memory.params.getParamA( |
131 GET_IP_NAME, GET_IP_CATEGORY, use_default=False | |
132 ) | |
122 | 133 |
123 if allow_get_ip is None: | 134 if allow_get_ip is None: |
124 # we don't have autorisation from user yet to use get_ip, we ask him | 135 # we don't have autorisation from user yet to use get_ip, we ask him |
125 def setParam(allowed): | 136 def setParam(allowed): |
126 # FIXME: we need to use boolConst as setParam only manage str/unicode | 137 # FIXME: we need to use boolConst as setParam only manage str/unicode |
127 # need to be fixed when params will be refactored | 138 # need to be fixed when params will be refactored |
128 self.host.memory.setParam(GET_IP_NAME, C.boolConst(allowed), GET_IP_CATEGORY) | 139 self.host.memory.setParam( |
140 GET_IP_NAME, C.boolConst(allowed), GET_IP_CATEGORY | |
141 ) | |
129 return allowed | 142 return allowed |
130 d = xml_tools.deferConfirm(self.host, _(GET_IP_CONFIRM), _(GET_IP_CONFIRM_TITLE), profile=client.profile) | 143 |
144 d = xml_tools.deferConfirm( | |
145 self.host, | |
146 _(GET_IP_CONFIRM), | |
147 _(GET_IP_CONFIRM_TITLE), | |
148 profile=client.profile, | |
149 ) | |
131 d.addCallback(setParam) | 150 d.addCallback(setParam) |
132 return d | 151 return d |
133 | 152 |
134 return defer.succeed(allow_get_ip) | 153 return defer.succeed(allow_get_ip) |
135 | 154 |
138 | 157 |
139 For now, just remove IPv4 local addresses | 158 For now, just remove IPv4 local addresses |
140 @param ip_addr(str): IP addresse | 159 @param ip_addr(str): IP addresse |
141 @return (bool): True if addresse is acceptable | 160 @return (bool): True if addresse is acceptable |
142 """ | 161 """ |
143 return not ip_addr.startswith('127.') | 162 return not ip_addr.startswith("127.") |
144 | 163 |
145 def _insertFirst(self, addresses, ip_addr): | 164 def _insertFirst(self, addresses, ip_addr): |
146 """Insert ip_addr as first item in addresses | 165 """Insert ip_addr as first item in addresses |
147 | 166 |
148 @param ip_addr(str): IP addresse | 167 @param ip_addr(str): IP addresse |
162 @return (D(str)): return local IP | 181 @return (D(str)): return local IP |
163 """ | 182 """ |
164 url = urlparse.urlparse(ext_url) | 183 url = urlparse.urlparse(ext_url) |
165 port = url.port | 184 port = url.port |
166 if port is None: | 185 if port is None: |
167 if url.scheme=='http': | 186 if url.scheme == "http": |
168 port = 80 | 187 port = 80 |
169 elif url.scheme=='https': | 188 elif url.scheme == "https": |
170 port = 443 | 189 port = 443 |
171 else: | 190 else: |
172 log.error(u"Unknown url scheme: {}".format(url.scheme)) | 191 log.error(u"Unknown url scheme: {}".format(url.scheme)) |
173 defer.returnValue(None) | 192 defer.returnValue(None) |
174 if url.hostname is None: | 193 if url.hostname is None: |
175 log.error(u"Can't find url hostname for {}".format(GET_IP_PAGE)) | 194 log.error(u"Can't find url hostname for {}".format(GET_IP_PAGE)) |
176 | 195 |
177 point = endpoints.TCP4ClientEndpoint(reactor, url.hostname, port) | 196 point = endpoints.TCP4ClientEndpoint(reactor, url.hostname, port) |
197 | |
178 def gotConnection(p): | 198 def gotConnection(p): |
179 local_ip = p.transport.getHost().host | 199 local_ip = p.transport.getHost().host |
180 p.transport.loseConnection() | 200 p.transport.loseConnection() |
181 return local_ip | 201 return local_ip |
182 | 202 |
194 """ | 214 """ |
195 # TODO: manage permission requesting (e.g. for UMTS link) | 215 # TODO: manage permission requesting (e.g. for UMTS link) |
196 if self._local_ip_cache is not None: | 216 if self._local_ip_cache is not None: |
197 defer.returnValue(self._local_ip_cache) | 217 defer.returnValue(self._local_ip_cache) |
198 addresses = [] | 218 addresses = [] |
199 localhost = ['127.0.0.1'] | 219 localhost = ["127.0.0.1"] |
200 | 220 |
201 # we first try our luck with netifaces | 221 # we first try our luck with netifaces |
202 if netifaces is not None: | 222 if netifaces is not None: |
203 addresses = [] | 223 addresses = [] |
204 for interface in netifaces.interfaces(): | 224 for interface in netifaces.interfaces(): |
206 try: | 226 try: |
207 inet_list = if_addresses[netifaces.AF_INET] | 227 inet_list = if_addresses[netifaces.AF_INET] |
208 except KeyError: | 228 except KeyError: |
209 continue | 229 continue |
210 for data in inet_list: | 230 for data in inet_list: |
211 addresse = data['addr'] | 231 addresse = data["addr"] |
212 if self._filterAddresse(addresse): | 232 if self._filterAddresse(addresse): |
213 addresses.append(addresse) | 233 addresses.append(addresse) |
214 | 234 |
215 # then we use our connection to server | 235 # then we use our connection to server |
216 ip = client.xmlstream.transport.getHost().host | 236 ip = client.xmlstream.transport.getHost().host |
249 @return (deferred): external IP address or None if it can't be discovered | 269 @return (deferred): external IP address or None if it can't be discovered |
250 """ | 270 """ |
251 if self._external_ip_cache is not None: | 271 if self._external_ip_cache is not None: |
252 defer.returnValue(self._external_ip_cache) | 272 defer.returnValue(self._external_ip_cache) |
253 | 273 |
254 | |
255 # we first try with XEP-0279 | 274 # we first try with XEP-0279 |
256 ip_check = yield self.host.hasFeature(client, NS_IP_CHECK) | 275 ip_check = yield self.host.hasFeature(client, NS_IP_CHECK) |
257 if ip_check: | 276 if ip_check: |
258 log.debug(u"Server IP Check available, we use it to retrieve our IP") | 277 log.debug(u"Server IP Check available, we use it to retrieve our IP") |
259 iq_elt = client.IQ("get") | 278 iq_elt = client.IQ("get") |
260 iq_elt.addElement((NS_IP_CHECK, 'address')) | 279 iq_elt.addElement((NS_IP_CHECK, "address")) |
261 try: | 280 try: |
262 result_elt = yield iq_elt.send() | 281 result_elt = yield iq_elt.send() |
263 address_elt = result_elt.elements(NS_IP_CHECK, 'address').next() | 282 address_elt = result_elt.elements(NS_IP_CHECK, "address").next() |
264 ip_elt = address_elt.elements(NS_IP_CHECK,'ip').next() | 283 ip_elt = address_elt.elements(NS_IP_CHECK, "ip").next() |
265 except StopIteration: | 284 except StopIteration: |
266 log.warning(u"Server returned invalid result on XEP-0279 request, we ignore it") | 285 log.warning( |
286 u"Server returned invalid result on XEP-0279 request, we ignore it" | |
287 ) | |
267 except StanzaError as e: | 288 except StanzaError as e: |
268 log.warning(u"error while requesting ip to server: {}".format(e)) | 289 log.warning(u"error while requesting ip to server: {}".format(e)) |
269 else: | 290 else: |
270 # FIXME: server IP may not be the same as external IP (server can be on local machine or network) | 291 # FIXME: server IP may not be the same as external IP (server can be on local machine or network) |
271 # IP should be checked to see if we have a local one, and rejected in this case | 292 # IP should be checked to see if we have a local one, and rejected in this case |
287 ip = (yield webclient.getPage(GET_IP_PAGE)) if allow_get_ip else None | 308 ip = (yield webclient.getPage(GET_IP_PAGE)) if allow_get_ip else None |
288 except (internet_error.DNSLookupError, internet_error.TimeoutError): | 309 except (internet_error.DNSLookupError, internet_error.TimeoutError): |
289 log.warning(u"Can't access Domain Name System") | 310 log.warning(u"Can't access Domain Name System") |
290 ip = None | 311 ip = None |
291 except web_error.Error as e: | 312 except web_error.Error as e: |
292 log.warning(u"Error while retrieving IP on {url}: {message}".format(url=GET_IP_PAGE, message=e)) | 313 log.warning( |
314 u"Error while retrieving IP on {url}: {message}".format( | |
315 url=GET_IP_PAGE, message=e | |
316 ) | |
317 ) | |
293 ip = None | 318 ip = None |
294 else: | 319 else: |
295 self._external_ip_cache = ip | 320 self._external_ip_cache = ip |
296 defer.returnValue(ip) | 321 defer.returnValue(ip) |
297 | 322 |
298 | 323 |
299 class IPPlugin_handler(XMPPHandler): | 324 class IPPlugin_handler(XMPPHandler): |
300 implements(iwokkel.IDisco) | 325 implements(iwokkel.IDisco) |
301 | 326 |
302 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | 327 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): |
303 return [disco.DiscoFeature(NS_IP_CHECK)] | 328 return [disco.DiscoFeature(NS_IP_CHECK)] |
304 | 329 |
305 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | 330 def getDiscoItems(self, requestor, target, nodeIdentifier=""): |
306 return [] | 331 return [] |