[MerlinSkinThemes] - add support for layouts
[enigma2-plugins.git] / webinterface / src / plugin.py
1 Version = '$Header$';
2
3 from enigma import eConsoleAppContainer, eTPM
4 from Plugins.Plugin import PluginDescriptor
5
6 from Components.config import config, ConfigBoolean, ConfigSubsection, ConfigInteger, ConfigYesNo, ConfigText, ConfigOnOff
7 from Components.Network import iNetworkInfo
8 from Screens.MessageBox import MessageBox
9 from WebIfConfig import WebIfConfigScreen
10 from WebChilds.Toplevel import getToplevel
11 from Tools.HardwareInfo import HardwareInfo
12
13 from Tools.Directories import copyfile, resolveFilename, SCOPE_PLUGINS, SCOPE_CONFIG
14 from Tools.IO import saveFile
15 from Tools.Log import Log
16
17 from twisted.internet import reactor, ssl
18 from twisted.internet.error import CannotListenError
19 from twisted.web import server, http, util, static, resource
20
21 from zope.interface import Interface, implements
22 from socket import gethostname as socket_gethostname
23 from OpenSSL import SSL, crypto
24 from time import gmtime
25 from os.path import isfile as os_isfile, exists as os_exists
26
27 from __init__ import __version__, decrypt_block
28 from webif import get_random, validate_certificate
29
30 import random, uuid, time, hashlib
31
32 from netaddr import IPNetwork
33
34 tpm = eTPM()
35 rootkey = ['\x9f', '|', '\xe4', 'G', '\xc9', '\xb4', '\xf4', '#', '&', '\xce', '\xb3', '\xfe', '\xda', '\xc9', 'U', '`', '\xd8', '\x8c', 's', 'o', '\x90', '\x9b', '\\', 'b', '\xc0', '\x89', '\xd1', '\x8c', '\x9e', 'J', 'T', '\xc5', 'X', '\xa1', '\xb8', '\x13', '5', 'E', '\x02', '\xc9', '\xb2', '\xe6', 't', '\x89', '\xde', '\xcd', '\x9d', '\x11', '\xdd', '\xc7', '\xf4', '\xe4', '\xe4', '\xbc', '\xdb', '\x9c', '\xea', '}', '\xad', '\xda', 't', 'r', '\x9b', '\xdc', '\xbc', '\x18', '3', '\xe7', '\xaf', '|', '\xae', '\x0c', '\xe3', '\xb5', '\x84', '\x8d', '\r', '\x8d', '\x9d', '2', '\xd0', '\xce', '\xd5', 'q', '\t', '\x84', 'c', '\xa8', ')', '\x99', '\xdc', '<', '"', 'x', '\xe8', '\x87', '\x8f', '\x02', ';', 'S', 'm', '\xd5', '\xf0', '\xa3', '_', '\xb7', 'T', '\t', '\xde', '\xa7', '\xf1', '\xc9', '\xae', '\x8a', '\xd7', '\xd2', '\xcf', '\xb2', '.', '\x13', '\xfb', '\xac', 'j', '\xdf', '\xb1', '\x1d', ':', '?']
36 hw = HardwareInfo()
37 #CONFIG INIT
38
39 #init the config
40 config.plugins.Webinterface = ConfigSubsection()
41 config.plugins.Webinterface.enabled = ConfigYesNo(default=True)
42 config.plugins.Webinterface.show_in_extensionsmenu = ConfigYesNo(default = False)
43 config.plugins.Webinterface.allowzapping = ConfigYesNo(default=True)
44 config.plugins.Webinterface.includemedia = ConfigYesNo(default=False)
45 config.plugins.Webinterface.autowritetimer = ConfigYesNo(default=False)
46 config.plugins.Webinterface.loadmovielength = ConfigYesNo(default=True)
47 config.plugins.Webinterface.version = ConfigText(__version__) # used to make the versioninfo accessible enigma2-wide, not confgurable in GUI.
48
49 config.plugins.Webinterface.http = ConfigSubsection()
50 config.plugins.Webinterface.http.enabled = ConfigYesNo(default=True)
51 config.plugins.Webinterface.http.port = ConfigInteger(default = 80, limits=(1, 65535) )
52 config.plugins.Webinterface.http.auth = ConfigYesNo(default=True)
53
54 config.plugins.Webinterface.https = ConfigSubsection()
55 config.plugins.Webinterface.https.enabled = ConfigYesNo(default=True)
56 config.plugins.Webinterface.https.port = ConfigInteger(default = 443, limits=(1, 65535) )
57 config.plugins.Webinterface.https.auth = ConfigYesNo(default=True)
58
59 config.plugins.Webinterface.streamauth = ConfigYesNo(default=False)
60 config.plugins.Webinterface.localauth = ConfigOnOff(default=False)
61
62 config.plugins.Webinterface.anti_hijack = ConfigOnOff(default=True)
63 config.plugins.Webinterface.extended_security = ConfigOnOff(default=True)
64
65 global running_defered, waiting_shutdown, toplevel
66
67 running_defered = []
68 waiting_shutdown = 0
69 toplevel = None
70 server.VERSION = "Enigma2 WebInterface Server $Revision$".replace("$Revi", "").replace("sion: ", "").replace("$", "")
71
72 KEY_FILE = resolveFilename(SCOPE_CONFIG, "key.pem")
73 CERT_FILE = resolveFilename(SCOPE_CONFIG, "cert.pem")
74
75 #===============================================================================
76 # Helperclass to close running Instances of the Webinterface
77 #===============================================================================
78 class Closer:
79         counter = 0
80         def __init__(self, session, callback=None, l2k=None):
81                 self.callback = callback
82                 self.session = session
83                 self.l2k = l2k
84 #===============================================================================
85 # Closes all running Instances of the Webinterface
86 #===============================================================================
87         def stop(self):
88                 global running_defered
89                 for d in running_defered:
90                         print "[Webinterface] stopping interface on ", d.interface, " with port", d.port
91                         x = d.stopListening()
92
93                         try:
94                                 x.addCallback(self.isDown)
95                                 self.counter += 1
96                         except AttributeError:
97                                 pass
98                 running_defered = []
99                 if self.counter < 1:
100                         if self.callback is not None:
101                                 self.callback(self.session, self.l2k)
102
103 #===============================================================================
104 # #Is it already down?
105 #===============================================================================
106         def isDown(self, s):
107                 self.counter -= 1
108                 if self.counter < 1:
109                         if self.callback is not None:
110                                 self.callback(self.session, self.l2k)
111
112 def installCertificates(session):
113         if not os_exists(CERT_FILE) \
114                         or not os_exists(KEY_FILE):
115                 print "[Webinterface].installCertificates :: Generating SSL key pair and CACert"
116                 # create a key pair
117                 k = crypto.PKey()
118                 k.generate_key(crypto.TYPE_RSA, 2048)
119
120                 # create a self-signed cert
121                 cert = crypto.X509()
122                 cert.get_subject().C = "DE"
123                 cert.get_subject().ST = "Home"
124                 cert.get_subject().L = "Home"
125                 cert.get_subject().O = "Dreambox"
126                 cert.get_subject().OU = "STB"
127                 cert.get_subject().CN = socket_gethostname()
128                 cert.set_serial_number(random.randint(1000000,1000000000))
129                 cert.set_notBefore("20120101000000Z");
130                 cert.set_notAfter("20301231235900Z")
131                 cert.set_issuer(cert.get_subject())
132                 cert.set_pubkey(k)
133                 print "[Webinterface].installCertificates :: Signing SSL key pair with new CACert"
134                 cert.sign(k, 'sha256')
135
136                 try:
137                         print "[Webinterface].installCertificates ::  Installing newly generated certificate and key pair"
138                         saveFile(CERT_FILE, crypto.dump_certificate(crypto.FILETYPE_PEM, cert))
139                         saveFile(KEY_FILE, crypto.dump_privatekey(crypto.FILETYPE_PEM, k))
140                 except IOError, e:
141                         #Disable https
142                         config.plugins.Webinterface.https.enabled.value = False
143                         config.plugins.Webinterface.https.enabled.save()
144                         #Inform the user
145                         session.open(MessageBox, "Couldn't install generated SSL-Certifactes for https access\nHttps access is disabled!", MessageBox.TYPE_ERROR)
146
147
148 #===============================================================================
149 # restart the Webinterface for all configured Interfaces
150 #===============================================================================
151 def restartWebserver(session, l2k):
152         try:
153                 del session.mediaplayer
154                 del session.messageboxanswer
155         except NameError:
156                 pass
157         except AttributeError:
158                 pass
159
160         global running_defered
161         if len(running_defered) > 0:
162                 Closer(session, startWebserver, l2k).stop()
163         else:
164                 startWebserver(session, l2k)
165
166 #===============================================================================
167 # start the Webinterface for all configured Interfaces
168 #===============================================================================
169 def startWebserver(session, l2k):
170         global running_defered
171         global toplevel
172
173         session.mediaplayer = None
174         session.messageboxanswer = None
175         if toplevel is None:
176                 toplevel = getToplevel(session)
177
178         errors = ""
179
180         if config.plugins.Webinterface.enabled.value is not True:
181                 print "[Webinterface] is disabled!"
182
183         else:
184                 # IF SSL is enabled we need to check for the certs first
185                 # If they're not there we'll exit via return here
186                 # and get called after Certificates are installed properly
187                 if config.plugins.Webinterface.https.enabled.value:
188                         installCertificates(session)
189
190                 # Listen on all Interfaces
191
192                 #HTTP
193                 port = config.plugins.Webinterface.http.port.value
194                 auth = config.plugins.Webinterface.http.auth.value
195                 if config.plugins.Webinterface.http.enabled.value is True:
196                         ret = startServerInstance(session, port, useauth=auth, l2k=l2k)
197                         if not ret:
198                                 errors = "%s port %i\n" %(errors, port)
199                         else:
200                                 registerBonjourService('http', port)
201
202                 #Streaming requires listening on localhost:80 no matter what, ensure it its available
203                 if config.plugins.Webinterface.http.port.value != 80 or not config.plugins.Webinterface.http.enabled.value:
204                         #LOCAL HTTP Connections (Streamproxy)
205                         local4 = "127.0.0.1"
206                         local4mapped = "::ffff:127.0.0.1"
207                         local6 = "::1"
208
209                         ret = startServerInstance(session, 80, useauth=auth, l2k=l2k, ipaddress=local4)
210                         if not ret:
211                                 errors = "%s%s:%i\n" %(errors, local4, 80)
212                         ret = startServerInstance(session, 80, useauth=auth, l2k=l2k, ipaddress=local4mapped, ipaddress2=local6)
213                         #ip6 is optional
214 #                       if not ret:
215 #                               errors = "%s%s/%s:%i\n" %(errors, local4mapped, local6, 80)
216
217                 #HTTPS
218                 if config.plugins.Webinterface.https.enabled.value is True:
219                         sport = config.plugins.Webinterface.https.port.value
220                         sauth = config.plugins.Webinterface.https.auth.value
221
222                         ret = startServerInstance(session, sport, useauth=sauth, l2k=l2k, usessl=True)
223                         if not ret:
224                                 errors = "%s%s:%i\n" %(errors, "0.0.0.0 / ::", sport)
225                         else:
226                                 registerBonjourService('https', sport)
227
228                 if errors:
229                         session.open(MessageBox, "Webinterface - Couldn't listen on:\n %s" % (errors), type=MessageBox.TYPE_ERROR, timeout=30)
230
231 #===============================================================================
232 # stop the Webinterface for all configured Interfaces
233 #===============================================================================
234 def stopWebserver(session):
235         try:
236                 del session.mediaplayer
237                 del session.messageboxanswer
238         except NameError:
239                 pass
240         except AttributeError:
241                 pass
242
243         global running_defered
244         if len(running_defered) > 0:
245                 Closer(session).stop()
246
247 #===============================================================================
248 # startServerInstance
249 # Starts an Instance of the Webinterface
250 # on given ipaddress, port, w/o auth, w/o ssl
251 #===============================================================================
252 def startServerInstance(session, port, useauth=False, l2k=None, usessl=False, ipaddress="::", ipaddress2=None):
253         l3k = None
254         l3c = tpm.getData(eTPM.DT_LEVEL3_CERT)
255
256         if l3c is None:
257                 return False
258
259         l3k = validate_certificate(l3c, l2k)
260         if l3k is None:
261                 return False
262
263         random = get_random()
264         if random is None:
265                 return False
266
267         value = tpm.computeSignature(random)
268         result = decrypt_block(value, l3k)
269
270         if result is None:
271                 return False
272         else:
273                 if result [80:88] != random:
274                         return False
275
276         if useauth:
277 # HTTPAuthResource handles the authentication for every Resource you want it to
278                 root = HTTPAuthResource(toplevel, "Enigma2 WebInterface")
279                 site = server.Site(root)
280         else:
281                 root = HTTPRootResource(toplevel)
282                 site = server.Site(root)
283
284         result = False
285
286         def logFail(addr, exception=None):
287                 print "[Webinterface] FAILED to listen on %s:%i auth=%s ssl=%s" % (addr, port, useauth, usessl)
288                 if exception:
289                         print exception
290
291         if usessl:
292                 ctx = ChainedOpenSSLContextFactory(KEY_FILE, CERT_FILE)
293                 try:
294                         d = reactor.listenSSL(port, site, ctx, interface=ipaddress)
295                         result = True
296                         running_defered.append(d)
297                 except CannotListenError as e:
298                         logFail(ipaddress, e)
299                 if ipaddress2:
300                         try:
301                                 d = reactor.listenSSL(port, site, ctx, interface=ipaddress2)
302                                 result = True
303                                 running_defered.append(d)
304                         except CannotListenError as e:
305                                 logFail(ipaddress2, e)
306         else:
307                 try:
308                         d = reactor.listenTCP(port, site, interface=ipaddress)
309                         result = True
310                         running_defered.append(d)
311                 except CannotListenError as e:
312                         logFail(ipaddress, e)
313                 if ipaddress2:
314                         try:
315                                 d = reactor.listenTCP(port, site, interface=ipaddress2)
316                                 result = True
317                                 running_defered.append(d)
318                         except CannotListenError as e:
319                                 logFail(ipaddress2, e)
320         
321         print "[Webinterface] started on %s:%i auth=%s ssl=%s" % (ipaddress, port, useauth, usessl)
322         return result
323
324         #except Exception, e:
325                 #print "[Webinterface] starting FAILED on %s:%i!" % (ipaddress, port), e
326                 #return False
327
328 class ChainedOpenSSLContextFactory(ssl.DefaultOpenSSLContextFactory):
329         def __init__(self, privateKeyFileName, certificateChainFileName, sslmethod=SSL.SSLv23_METHOD):
330                 self.privateKeyFileName = privateKeyFileName
331                 self.certificateChainFileName = certificateChainFileName
332                 self.sslmethod = sslmethod
333                 self.cacheContext()
334
335         def cacheContext(self):
336                 ctx = SSL.Context(self.sslmethod)
337                 ctx.set_options(SSL.OP_NO_SSLv3|SSL.OP_NO_SSLv2)
338                 ctx.use_certificate_chain_file(self.certificateChainFileName)
339                 ctx.use_privatekey_file(self.privateKeyFileName)
340                 self._context = ctx
341
342 class SimpleSession(object):
343         def __init__(self, expires=0):
344                 self._id = "0"
345                 self._expires = time.time() + expires if expires > 0 else 0
346
347         def _generateId(self):
348                 if config.plugins.Webinterface.extended_security.value:
349                         self._id = str ( uuid.uuid4() )
350                 else:
351                         self._id = "0"
352
353         def _getId(self):
354                 if self.expired():
355                         self._generateId()
356                 return self._id
357
358         def expired(self):
359                 expired = False
360                 if config.plugins.Webinterface.extended_security.value:
361                         expired = self._expires > 0 and self._expires < time.time()
362                         expired = expired or self._id == "0"
363                 else:
364                         expired = self._id != "0"
365                 return expired
366
367         id = property(_getId)
368
369 #Every request made will pass this Resource (as it is the root resource)
370 #Any "global" checks should be done here
371 class HTTPRootResource(resource.Resource):
372         SESSION_PROTECTED_PATHS = ['/web/', '/opkg', '/ipkg']
373         SESSION_EXCEPTIONS = [
374                 '/web/epgsearch.rss', '/web/movielist.m3u', '/web/movielist.rss', '/web/services.m3u', '/web/session',
375                 '/web/stream.m3u', '/web/stream', '/web/streamcurrent.m3u', '/web/strings.js', '/web/ts.m3u']
376
377         def __init__(self, res):
378                 print "[HTTPRootResource}.__init__"
379                 resource.Resource.__init__(self)
380                 self.resource = res
381                 self.sessionInvalidResource = resource.ErrorPage(http.PRECONDITION_FAILED, "Precondition failed!", "sessionid is missing, invalid or expired!")
382                 self._sessions = {}
383
384         def getClientToken(self, request):
385                 ip = request.getClientIP()
386                 ua = request.getHeader("User-Agent") or "Default UA"
387                 return hashlib.sha1("%s/%s" %(ip, ua)).hexdigest()
388
389         def isSessionValid(self, request):
390                 session = self._sessions.get( self.getClientToken(request), None )
391                 if session is None or session.expired():
392                         session = SimpleSession()
393                         key = self.getClientToken(request)
394                         print "[HTTPRootResource].isSessionValid :: created session with id '%s' for client with token '%s'" %(session.id, key)
395                         self._sessions[ key ] = session
396
397                 request.enigma2_session = session
398
399                 if config.plugins.Webinterface.extended_security.value and not request.path in self.SESSION_EXCEPTIONS:
400                         protected = False
401                         for path in self.SESSION_PROTECTED_PATHS:
402                                 if request.path.startswith(path):
403                                         protected = True
404
405                         if protected:
406                                 rsid = request.args.get('sessionid', None)
407                                 if rsid:
408                                         rsid = rsid[0]
409                                 return session and session.id == rsid
410
411                 return True
412
413         def render(self, request):
414                 #enable SAMEORIGIN policy for iframes
415                 if config.plugins.Webinterface.anti_hijack.value:
416                         request.setHeader("X-Frame-Options", "SAMEORIGIN")
417
418                 if self.isSessionValid(request):
419                         return self.resource.render(request)
420                 else:
421                         return self.sessionInvalidResource.render(request)
422
423         def getChildWithDefault(self, path, request):
424                 #enable SAMEORIGIN policy for iframes
425                 if config.plugins.Webinterface.anti_hijack.value:
426                         request.setHeader("X-Frame-Options", "SAMEORIGIN")
427
428                 if self.isSessionValid(request):
429                         return self.resource.getChildWithDefault(path, request)
430                 else:
431                         print "[Webinterface.HTTPRootResource.render] !!! session invalid !!!"
432                         return self.sessionInvalidResource
433
434 #===============================================================================
435 # HTTPAuthResource
436 # Handles HTTP Authorization for a given Resource
437 #===============================================================================
438 class HTTPAuthResource(HTTPRootResource):
439         LOCALHOSTS = (IPNetwork("127.0.0.1"), IPNetwork("::1"))
440
441         def __init__(self, res, realm):
442                 HTTPRootResource.__init__(self, res)
443                 self.realm = realm
444                 self.authorized = False
445                 self.unauthorizedResource = resource.ErrorPage(http.UNAUTHORIZED, "Access denied", "Authentication credentials invalid!")
446                 self._localNetworks = []
447
448         def _assignLocalNetworks(self, ifaces):
449                         if self._localNetworks:
450                                 return
451                         self._localNetworks = []
452                         #LAN
453                         for key, iface in ifaces.iteritems():
454                                 if iface.ipv4.address != "0.0.0.0":
455                                         v4net = IPNetwork("%s/%s" %(iface.ipv4.address, iface.ipv4.netmask))
456                                         self._localNetworks.append(v4net)
457                                 if iface.ipv6.address != "::":
458                                         v6net = IPNetwork("%s/%s" %(iface.ipv6.address, iface.ipv6.netmask))
459                                         self._localNetworks.append(v6net)
460                         Log.w(self._localNetworks)
461
462         def unauthorized(self, request):
463                 request.setHeader('WWW-authenticate', 'Basic realm="%s"' % self.realm)
464                 request.setResponseCode(http.UNAUTHORIZED)
465                 return self.unauthorizedResource
466
467         def _isLocalClient(self, clientip):
468                 if self._isLocalHost(clientip):
469                         return True
470                 for lnw in self._localNetworks:
471                         if self._networkContains(lnw, clientip):
472                                 return True
473                 return False
474
475         def _isLocalHost(self, clientip):
476                 for host in self.LOCALHOSTS:
477                         if self._networkContains(host, clientip):
478                                 return True
479                 return False
480
481         def _networkContains(self, network, ip):
482                 if network.__contains__(ip):
483                         return True
484                 try:
485                         # You may get an ipv6 noted ipv4 address like "::ffff:192.168.0.2"
486                         # In that case it won't match the ipv4 local network so we have to try converting it to plain ipv4
487                         if network.__contains__(ip.ipv4()):
488                                 return True
489                 except:
490                         pass
491                 return False
492
493         def isAuthenticated(self, request):
494                 self._assignLocalNetworks(iNetworkInfo.getConfiguredInterfaces())
495                 if request.transport:
496                         host = IPNetwork(request.transport.getPeer().host)
497                         #If streamauth is disabled allow all acces from localhost
498                         if not config.plugins.Webinterface.streamauth.value:
499                                 if self._isLocalHost(host.ip):
500                                         Log.i("Streaming auth is disabled - Bypassing Authcheck because host '%s' is local!" %host)
501                                         return True
502                         if not config.plugins.Webinterface.localauth.value:
503                                 if self._isLocalClient(host.ip):
504                                         Log.i("Local auth is disabled - Bypassing Authcheck because host '%s' is local!" %host)
505                                         return True
506
507                 # get the Session from the Request
508                 http_session = request.getSession().sessionNamespaces
509
510                 # if the auth-information has not yet been stored to the http_session
511                 if not http_session.has_key('authenticated'):
512                         if request.getUser() and request.getPassword():
513                                 http_session['authenticated'] = check_passwd(request.getUser(), request.getPassword())
514                         else:
515                                 http_session['authenticated'] = False
516
517                 #if the auth-information already is in the http_session
518                 else:
519                         if http_session['authenticated'] is False:
520                                 http_session['authenticated'] = check_passwd(request.getUser(), request.getPassword() )
521
522                 #return the current authentication status
523                 return http_session['authenticated']
524
525 #===============================================================================
526 # Call render of self.resource (if authenticated)
527 #===============================================================================
528         def render(self, request):
529                 if self.isAuthenticated(request) is True:
530                         return HTTPRootResource.render(self, request)
531                 else:
532                         print "[Webinterface.HTTPAuthResource.render] !!! unauthorized !!!"
533                         return self.unauthorized(request).render(request)
534
535 #===============================================================================
536 # Override to call getChildWithDefault of self.resource (if authenticated)
537 #===============================================================================
538         def getChildWithDefault(self, path, request):
539                 if self.isAuthenticated(request) is True:
540                         return HTTPRootResource.getChildWithDefault(self, path, request)
541                 else:
542                         print "[Webinterface.HTTPAuthResource.getChildWithDefault] !!! unauthorized !!!"
543                         return self.unauthorized(request)
544
545 from auth import check_passwd
546
547 global_session = None
548
549 #===============================================================================
550 # sessionstart
551 # Actions to take place on Session start
552 #===============================================================================
553 def sessionstart(reason, session):
554         global global_session
555         global_session = session
556         networkstart(True, session)
557
558
559 def registerBonjourService(protocol, port):
560         try:
561                 from Plugins.Extensions.Bonjour.Bonjour import bonjour
562
563                 service = bonjour.buildService(protocol, port)
564                 bonjour.registerService(service, True)
565                 print "[WebInterface.registerBonjourService] Service for protocol '%s' with port '%i' registered!" %(protocol, port)
566                 return True
567
568         except ImportError, e:
569                 print "[WebInterface.registerBonjourService] %s" %e
570                 return False
571
572 def unregisterBonjourService(protocol):
573         try:
574                 from Plugins.Extensions.Bonjour.Bonjour import bonjour
575
576                 bonjour.unregisterService(protocol)
577                 print "[WebInterface.unregisterBonjourService] Service for protocol '%s' unregistered!" %(protocol)
578                 return True
579
580         except ImportError, e:
581                 print "[WebInterface.unregisterBonjourService] %s" %e
582                 return False
583
584 def checkBonjour():
585         if ( not config.plugins.Webinterface.http.enabled.value ) or ( not config.plugins.Webinterface.enabled.value ):
586                 unregisterBonjourService('http')
587         if ( not config.plugins.Webinterface.https.enabled.value ) or ( not config.plugins.Webinterface.enabled.value ):
588                 unregisterBonjourService('https')
589
590 #===============================================================================
591 # networkstart
592 # Actions to take place after Network is up (startup the Webserver)
593 #===============================================================================
594 #def networkstart(reason, **kwargs):
595 def networkstart(reason, session):
596         l2r = False
597         l2k = None
598         l2c = tpm.getData(eTPM.DT_LEVEL2_CERT)
599
600         if l2c is None:
601                 return
602
603         l2k = validate_certificate(l2c, rootkey)
604         if l2k is None:
605                 return
606
607         if reason is True:
608                 startWebserver(session, l2k)
609                 checkBonjour()
610
611         elif reason is False:
612                 stopWebserver(session)
613                 checkBonjour()
614
615 def openconfig(session, **kwargs):
616         session.openWithCallback(configCB, WebIfConfigScreen)
617
618 def menu_config(menuid, **kwargs):
619         if menuid == "network":
620                 return [(_("Webinterface"), openconfig, "webif", 60)]
621         else:
622                 return []
623
624 def configCB(result, session):
625         l2r = False
626         l2k = None
627         l2c = tpm.getData(eTPM.DT_LEVEL2_CERT)
628
629         if l2c is None:
630                 return
631
632         l2k = validate_certificate(l2c, rootkey)
633         if l2k is None:
634                 return
635
636         if result:
637                 print "[WebIf] config changed"
638                 restartWebserver(session, l2k)
639                 checkBonjour()
640         else:
641                 print "[WebIf] config not changed"
642
643 def Plugins(**kwargs):
644         p = PluginDescriptor(where=[PluginDescriptor.WHERE_SESSIONSTART], fnc=sessionstart)
645         p.weight = 100 #webif should start as last plugin
646         list = [p,
647 #                       PluginDescriptor(where=[PluginDescriptor.WHERE_NETWORKCONFIG_READ], fnc=networkstart),
648                         PluginDescriptor(name=_("Webinterface"), description=_("Configuration for the Webinterface"),
649                                                         where=PluginDescriptor.WHERE_MENU, icon="plugin.png", fnc=menu_config)]
650         if config.plugins.Webinterface.show_in_extensionsmenu.value:
651                 list.append(PluginDescriptor(name="Webinterface", description=_("Configuration for the Webinterface"),
652                         where=PluginDescriptor.WHERE_EXTENSIONSMENU, icon="plugin.png", fnc=openconfig))
653         return list