1 # -*- test-case-name: twisted.conch.test.test_manhole -*-
2 # Copyright (c) Twisted Matrix Laboratories.
3 # See LICENSE for details.
6 insults/SSH integration support.
11 from zope.interface import implements
13 from twisted.conch import avatar, interfaces as iconch, error as econch
14 from twisted.conch.ssh import factory, keys, session
15 from twisted.cred import credentials, checkers, portal
16 from twisted.python import components
18 from twisted.conch.insults import insults
21 """A feeble class for making one attribute look like another.
23 This should be replaced with a real class at some point, probably.
24 Try not to write new code that uses it.
26 def __init__(self, **kw):
27 self.__dict__.update(kw)
29 def __getattr__(self, name):
30 raise AttributeError(self.name, "has no attribute", name)
32 class TerminalSessionTransport:
33 def __init__(self, proto, chainedProtocol, avatar, width, height):
36 self.chainedProtocol = chainedProtocol
38 session = self.proto.session
40 self.proto.makeConnection(
41 _Glue(write=self.chainedProtocol.dataReceived,
42 loseConnection=lambda: avatar.conn.sendClose(session),
43 name="SSH Proto Transport"))
46 self.proto.loseConnection()
48 self.chainedProtocol.makeConnection(
49 _Glue(write=self.proto.write,
50 loseConnection=loseConnection,
51 name="Chained Proto Transport"))
54 # chainedProtocol is supposed to be an ITerminalTransport,
55 # maybe. That means perhaps its terminalProtocol attribute is
56 # an ITerminalProtocol, it could be. So calling terminalSize
57 # on that should do the right thing But it'd be nice to clean
59 self.chainedProtocol.terminalProtocol.terminalSize(width, height)
61 class TerminalSession(components.Adapter):
62 implements(iconch.ISession)
64 transportFactory = TerminalSessionTransport
65 chainedProtocolFactory = insults.ServerProtocol
67 def getPty(self, term, windowSize, attrs):
68 self.height, self.width = windowSize[:2]
70 def openShell(self, proto):
71 self.transportFactory(
72 proto, self.chainedProtocolFactory(),
73 iconch.IConchUser(self.original),
74 self.width, self.height)
76 def execCommand(self, proto, cmd):
77 raise econch.ConchError("Cannot execute commands")
82 class TerminalUser(avatar.ConchUser, components.Adapter):
83 def __init__(self, original, avatarId):
84 components.Adapter.__init__(self, original)
85 avatar.ConchUser.__init__(self)
86 self.channelLookup['session'] = session.SSHSession
89 userFactory = TerminalUser
90 sessionFactory = TerminalSession
92 transportFactory = TerminalSessionTransport
93 chainedProtocolFactory = insults.ServerProtocol
95 def _getAvatar(self, avatarId):
96 comp = components.Componentized()
97 user = self.userFactory(comp, avatarId)
98 sess = self.sessionFactory(comp)
100 sess.transportFactory = self.transportFactory
101 sess.chainedProtocolFactory = self.chainedProtocolFactory
103 comp.setComponent(iconch.IConchUser, user)
104 comp.setComponent(iconch.ISession, sess)
108 def __init__(self, transportFactory=None):
109 if transportFactory is not None:
110 self.transportFactory = transportFactory
112 def requestAvatar(self, avatarId, mind, *interfaces):
114 if i is iconch.IConchUser:
115 return (iconch.IConchUser,
116 self._getAvatar(avatarId),
118 raise NotImplementedError()
120 class ConchFactory(factory.SSHFactory):
121 publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEArzJx8OYOnJmzf4tfBEvLi8DVPrJ3/c9k2I/Az64fxjHf9imyRJbixtQhlH9lfNjUIx+4LmrJH5QNRsFporcHDKOTwTTYLh5KmRpslkYHRivcJSkbh/C+BR3utDS555mV'
124 'ssh-rsa' : keys.Key.fromString(publicKey)
128 privateKey = """-----BEGIN RSA PRIVATE KEY-----
129 MIIByAIBAAJhAK8ycfDmDpyZs3+LXwRLy4vA1T6yd/3PZNiPwM+uH8Yx3/YpskSW
130 4sbUIZR/ZXzY1CMfuC5qyR+UDUbBaaK3Bwyjk8E02C4eSpkabJZGB0Yr3CUpG4fw
131 vgUd7rQ0ueeZlQIBIwJgbh+1VZfr7WftK5lu7MHtqE1S1vPWZQYE3+VUn8yJADyb
132 Z4fsZaCrzW9lkIqXkE3GIY+ojdhZhkO1gbG0118sIgphwSWKRxK0mvh6ERxKqIt1
133 xJEJO74EykXZV4oNJ8sjAjEA3J9r2ZghVhGN6V8DnQrTk24Td0E8hU8AcP0FVP+8
134 PQm/g/aXf2QQkQT+omdHVEJrAjEAy0pL0EBH6EVS98evDCBtQw22OZT52qXlAwZ2
135 gyTriKFVoqjeEjt3SZKKqXHSApP/AjBLpF99zcJJZRq2abgYlf9lv1chkrWqDHUu
136 DZttmYJeEfiFBBavVYIF1dOlZT0G8jMCMBc7sOSZodFnAiryP+Qg9otSBjJ3bQML
137 pSTqy7c3a2AScC/YyOwkDaICHnnD3XyjMwIxALRzl0tQEKMXs6hH8ToUdlLROCrP
138 EhQ0wahUTCk1gKA4uPD6TMTChavbh4K63OvbKg==
139 -----END RSA PRIVATE KEY-----"""
141 'ssh-rsa' : keys.Key.fromString(privateKey)
145 def __init__(self, portal):