| OLD | NEW |
| (Empty) |
| 1 # -*- test-case-name: twisted.conch.test.test_manhole -*- | |
| 2 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
| 3 # See LICENSE for details. | |
| 4 | |
| 5 """ | |
| 6 insults/SSH integration support. | |
| 7 | |
| 8 @author: U{Jp Calderone<mailto:exarkun@twistedmatrix.com>} | |
| 9 """ | |
| 10 | |
| 11 from zope.interface import implements | |
| 12 | |
| 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 | |
| 17 | |
| 18 from twisted.conch.insults import insults | |
| 19 | |
| 20 class _Glue: | |
| 21 """A feeble class for making one attribute look like another. | |
| 22 | |
| 23 This should be replaced with a real class at some point, probably. | |
| 24 Try not to write new code that uses it. | |
| 25 """ | |
| 26 def __init__(self, **kw): | |
| 27 self.__dict__.update(kw) | |
| 28 | |
| 29 def __getattr__(self, name): | |
| 30 raise AttributeError(self.name, "has no attribute", name) | |
| 31 | |
| 32 class TerminalSessionTransport: | |
| 33 def __init__(self, proto, chainedProtocol, avatar, width, height): | |
| 34 self.proto = proto | |
| 35 self.avatar = avatar | |
| 36 self.chainedProtocol = chainedProtocol | |
| 37 | |
| 38 session = self.proto.session | |
| 39 | |
| 40 self.proto.makeConnection( | |
| 41 _Glue(write=self.chainedProtocol.dataReceived, | |
| 42 loseConnection=lambda: avatar.conn.sendClose(session), | |
| 43 name="SSH Proto Transport")) | |
| 44 | |
| 45 def loseConnection(): | |
| 46 self.proto.loseConnection() | |
| 47 | |
| 48 self.chainedProtocol.makeConnection( | |
| 49 _Glue(write=self.proto.write, | |
| 50 loseConnection=loseConnection, | |
| 51 name="Chained Proto Transport")) | |
| 52 | |
| 53 # XXX TODO | |
| 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 | |
| 58 # this bit up. | |
| 59 self.chainedProtocol.terminalProtocol.terminalSize(width, height) | |
| 60 | |
| 61 class TerminalSession(components.Adapter): | |
| 62 implements(iconch.ISession) | |
| 63 | |
| 64 transportFactory = TerminalSessionTransport | |
| 65 chainedProtocolFactory = insults.ServerProtocol | |
| 66 | |
| 67 def getPty(self, term, windowSize, attrs): | |
| 68 self.height, self.width = windowSize[:2] | |
| 69 | |
| 70 def openShell(self, proto): | |
| 71 self.transportFactory( | |
| 72 proto, self.chainedProtocolFactory(), | |
| 73 iconch.IConchUser(self.original), | |
| 74 self.width, self.height) | |
| 75 | |
| 76 def execCommand(self, proto, cmd): | |
| 77 raise econch.ConchError("Cannot execute commands") | |
| 78 | |
| 79 def closed(self): | |
| 80 pass | |
| 81 | |
| 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 | |
| 87 | |
| 88 class TerminalRealm: | |
| 89 userFactory = TerminalUser | |
| 90 sessionFactory = TerminalSession | |
| 91 | |
| 92 transportFactory = TerminalSessionTransport | |
| 93 chainedProtocolFactory = insults.ServerProtocol | |
| 94 | |
| 95 def _getAvatar(self, avatarId): | |
| 96 comp = components.Componentized() | |
| 97 user = self.userFactory(comp, avatarId) | |
| 98 sess = self.sessionFactory(comp) | |
| 99 | |
| 100 sess.transportFactory = self.transportFactory | |
| 101 sess.chainedProtocolFactory = self.chainedProtocolFactory | |
| 102 | |
| 103 comp.setComponent(iconch.IConchUser, user) | |
| 104 comp.setComponent(iconch.ISession, sess) | |
| 105 | |
| 106 return user | |
| 107 | |
| 108 def __init__(self, transportFactory=None): | |
| 109 if transportFactory is not None: | |
| 110 self.transportFactory = transportFactory | |
| 111 | |
| 112 def requestAvatar(self, avatarId, mind, *interfaces): | |
| 113 for i in interfaces: | |
| 114 if i is iconch.IConchUser: | |
| 115 return (iconch.IConchUser, | |
| 116 self._getAvatar(avatarId), | |
| 117 lambda: None) | |
| 118 raise NotImplementedError() | |
| 119 | |
| 120 class ConchFactory(factory.SSHFactory): | |
| 121 publicKey = 'ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAGEArzJx8OYOnJmzf4tfBEvLi8DVPrJ
3/c9k2I/Az64fxjHf9imyRJbixtQhlH9lfNjUIx+4LmrJH5QNRsFporcHDKOTwTTYLh5KmRpslkYHRiv
cJSkbh/C+BR3utDS555mV' | |
| 122 | |
| 123 publicKeys = { | |
| 124 'ssh-rsa' : keys.Key.fromString(publicKey) | |
| 125 } | |
| 126 del publicKey | |
| 127 | |
| 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-----""" | |
| 140 privateKeys = { | |
| 141 'ssh-rsa' : keys.Key.fromString(privateKey) | |
| 142 } | |
| 143 del privateKey | |
| 144 | |
| 145 def __init__(self, portal): | |
| 146 self.portal = portal | |
| OLD | NEW |