lightpacket 0.0.3a0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lightpacket-0.0.3a0/LightPacket/Arp.py +201 -0
- lightpacket-0.0.3a0/LightPacket/BaseLayer.py +145 -0
- lightpacket-0.0.3a0/LightPacket/Consts.py +644 -0
- lightpacket-0.0.3a0/LightPacket/Decoration/Colors.py +30 -0
- lightpacket-0.0.3a0/LightPacket/Decoration/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/Detect_layer.py +70 -0
- lightpacket-0.0.3a0/LightPacket/Dot3.py +186 -0
- lightpacket-0.0.3a0/LightPacket/EthernetII.py +243 -0
- lightpacket-0.0.3a0/LightPacket/GetIPv4.py +27 -0
- lightpacket-0.0.3a0/LightPacket/GetMac.py +51 -0
- lightpacket-0.0.3a0/LightPacket/Hex.py +14 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/LibpcapInterfacesLin.py +369 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/LibpcapInterfacesUnix.py +214 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/LinuxInterfaces.py +340 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/NpcapInterfacesWin.py +62 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/UnixInterfaces.py +410 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/WinInterfaces.py +680 -0
- lightpacket-0.0.3a0/LightPacket/Interfaces/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/LLC.py +130 -0
- lightpacket-0.0.3a0/LightPacket/Layers/IPtoa.py +68 -0
- lightpacket-0.0.3a0/LightPacket/Layers/IS_LLC.py +18 -0
- lightpacket-0.0.3a0/LightPacket/Layers/L2Socket.py +354 -0
- lightpacket-0.0.3a0/LightPacket/Layers/L2SocketL.py +484 -0
- lightpacket-0.0.3a0/LightPacket/Layers/Mac.py +47 -0
- lightpacket-0.0.3a0/LightPacket/Layers/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/Layers/get_layers.py +30 -0
- lightpacket-0.0.3a0/LightPacket/LightPacketLin.py +23 -0
- lightpacket-0.0.3a0/LightPacket/LightPacketUnix.py +26 -0
- lightpacket-0.0.3a0/LightPacket/LightPacketWin.py +25 -0
- lightpacket-0.0.3a0/LightPacket/Logger/Errors.py +24 -0
- lightpacket-0.0.3a0/LightPacket/Logger/LightLogger.py +62 -0
- lightpacket-0.0.3a0/LightPacket/Logger/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/Raw.py +85 -0
- lightpacket-0.0.3a0/LightPacket/Saving/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/Saving/pcapreader.py +89 -0
- lightpacket-0.0.3a0/LightPacket/Saving/pcapwriter.py +56 -0
- lightpacket-0.0.3a0/LightPacket/Snap.py +136 -0
- lightpacket-0.0.3a0/LightPacket/Stp.py +216 -0
- lightpacket-0.0.3a0/LightPacket/Version.py +5 -0
- lightpacket-0.0.3a0/LightPacket/Vlan.py +148 -0
- lightpacket-0.0.3a0/LightPacket/__init__.py +19 -0
- lightpacket-0.0.3a0/LightPacket/bpf.py +98 -0
- lightpacket-0.0.3a0/LightPacket/data/oui.txt +239865 -0
- lightpacket-0.0.3a0/LightPacket/eapol.py +3022 -0
- lightpacket-0.0.3a0/LightPacket/helper/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/helper/ls.py +46 -0
- lightpacket-0.0.3a0/LightPacket/helper/network.py +61 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/ARP.json +17 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/Beacon.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/Dot3.json +10 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAPOL.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_FAST.json +18 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_GTC.json +13 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_IDENTITY.json +13 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_Key.json +19 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_LEAP.json +17 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_MD5.json +15 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_MSCHAPv2.json +20 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_NAK.json +13 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_NOTIFICATION.json +13 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_OTP.json +13 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_PEAP.json +19 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_PWD.json +17 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_STATE.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_TLS.json +18 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/EAP_TTLS.json +19 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/Element.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/Ethernet.json +10 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/ISL.json +20 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/LLC.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/PPP.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/PPP2b.json +9 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/PPPoE.json +13 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/ProbeRequest.json +9 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/ProbeResponse.json +11 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/Raw.json +9 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/SNAP.json +10 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/STP.json +22 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/VLAN.json +12 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/WiFi.json +20 -0
- lightpacket-0.0.3a0/LightPacket/helper/protos/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/images/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/isl.py +293 -0
- lightpacket-0.0.3a0/LightPacket/l2.py +24 -0
- lightpacket-0.0.3a0/LightPacket/lib/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/lib/libpcap_reader.so +0 -0
- lightpacket-0.0.3a0/LightPacket/lib/libpcap_writer.so +0 -0
- lightpacket-0.0.3a0/LightPacket/ppp.py +305 -0
- lightpacket-0.0.3a0/LightPacket/utils/CIDR.py +618 -0
- lightpacket-0.0.3a0/LightPacket/utils/FCS.py +65 -0
- lightpacket-0.0.3a0/LightPacket/utils/Nsec/__init__.py +1 -0
- lightpacket-0.0.3a0/LightPacket/utils/Nsec/arp_resolution.py +38 -0
- lightpacket-0.0.3a0/LightPacket/utils/VlanUtils.py +65 -0
- lightpacket-0.0.3a0/LightPacket/utils/__init__.py +1 -0
- lightpacket-0.0.3a0/PKG-INFO +1500 -0
- lightpacket-0.0.3a0/README.md +1486 -0
- lightpacket-0.0.3a0/lightpacket.egg-info/PKG-INFO +1500 -0
- lightpacket-0.0.3a0/lightpacket.egg-info/SOURCES.txt +101 -0
- lightpacket-0.0.3a0/lightpacket.egg-info/dependency_links.txt +1 -0
- lightpacket-0.0.3a0/lightpacket.egg-info/not-zip-safe +1 -0
- lightpacket-0.0.3a0/lightpacket.egg-info/top_level.txt +1 -0
- lightpacket-0.0.3a0/setup.cfg +4 -0
- lightpacket-0.0.3a0/setup.py +34 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
import struct
|
|
7
|
+
|
|
8
|
+
from .GetMac import GetMac
|
|
9
|
+
from .GetIPv4 import GetIPv4Gateway,GetIPv4
|
|
10
|
+
from .Decoration.Colors import RESET, CYAN, BLUE, PURPLE, BOLD
|
|
11
|
+
from .Logger.LightLogger import Logger, ErrorCode
|
|
12
|
+
from .BaseLayer import BaseLayer
|
|
13
|
+
from typing import Union
|
|
14
|
+
from .Layers.Mac import MacAddress
|
|
15
|
+
from .Layers.IPtoa import inet_aton, inet_ntoa
|
|
16
|
+
from .Consts import HWTYPES,ETHERTYPE,BROADCAST_MAC,IPv4,MC,OUI_MAP
|
|
17
|
+
|
|
18
|
+
LLogger = Logger()
|
|
19
|
+
|
|
20
|
+
"""
|
|
21
|
+
Arp Layer Creation (class ARP)
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
class ARP(BaseLayer):
|
|
25
|
+
|
|
26
|
+
def __init__(self, hwtype: int = None, ptype: int = None, maclen: int = None,
|
|
27
|
+
plen: int = None, opcode: int = None, macsrc: Union[str, bytes] = None,
|
|
28
|
+
ipsrc: str = None, macdst: Union[str, bytes] = None, ipdst: str = None):
|
|
29
|
+
super().__init__()
|
|
30
|
+
if macsrc is None:
|
|
31
|
+
macsrc = GetMac()
|
|
32
|
+
if macdst is None:
|
|
33
|
+
macdst = BROADCAST_MAC
|
|
34
|
+
if hwtype is None:
|
|
35
|
+
hwtype = 1
|
|
36
|
+
if ptype is None:
|
|
37
|
+
ptype = IPv4
|
|
38
|
+
if maclen is None:
|
|
39
|
+
maclen = 6
|
|
40
|
+
if plen is None:
|
|
41
|
+
plen = 4
|
|
42
|
+
if opcode is None:
|
|
43
|
+
opcode = 1
|
|
44
|
+
if ipsrc is None:
|
|
45
|
+
ipsrc = GetIPv4()
|
|
46
|
+
if ipdst is None:
|
|
47
|
+
ipdst = GetIPv4Gateway()
|
|
48
|
+
|
|
49
|
+
self.hwtype = hwtype
|
|
50
|
+
self.ptype = ptype
|
|
51
|
+
self.maclen = maclen
|
|
52
|
+
self.plen = plen
|
|
53
|
+
self.opcode = opcode
|
|
54
|
+
self.macsrc = MacAddress(macsrc, d_or_s=0)
|
|
55
|
+
self.ipsrc = ipsrc
|
|
56
|
+
self.macdst = MacAddress(macdst, d_or_s=1)
|
|
57
|
+
self.ipdst = ipdst
|
|
58
|
+
|
|
59
|
+
def build(self) -> bytes:
|
|
60
|
+
|
|
61
|
+
arp = struct.pack(
|
|
62
|
+
'!HHBBH6s4s6s4s',
|
|
63
|
+
self.hwtype,
|
|
64
|
+
self.ptype,
|
|
65
|
+
self.maclen,
|
|
66
|
+
self.plen,
|
|
67
|
+
self.opcode,
|
|
68
|
+
bytes(self.macsrc),
|
|
69
|
+
inet_aton(self.ipsrc),
|
|
70
|
+
bytes(self.macdst),
|
|
71
|
+
inet_aton(self.ipdst),
|
|
72
|
+
)
|
|
73
|
+
if self.payload:
|
|
74
|
+
return arp + self.payload.build()
|
|
75
|
+
return arp
|
|
76
|
+
|
|
77
|
+
def __len__(self):
|
|
78
|
+
return 28
|
|
79
|
+
|
|
80
|
+
def __repr__(self):
|
|
81
|
+
return (
|
|
82
|
+
f"<Arp opcode={self.opcode} plen={self.plen} ptype={hex(self.ptype)} maclen={self.maclen} hwtype={self.hwtype} macsrc={self.macsrc} ipsrc={self.ipsrc} macdst={self.macdst} ipdst={self.ipdst}>")
|
|
83
|
+
|
|
84
|
+
def copy(self) -> 'ARP':
|
|
85
|
+
new_layer = ARP(
|
|
86
|
+
hwtype=self.hwtype,
|
|
87
|
+
ptype=self.ptype,
|
|
88
|
+
maclen=self.maclen,
|
|
89
|
+
plen=self.plen,
|
|
90
|
+
opcode=self.opcode,
|
|
91
|
+
macsrc=str(self.macsrc),
|
|
92
|
+
ipsrc=self.ipsrc,
|
|
93
|
+
macdst=str(self.macdst),
|
|
94
|
+
ipdst=self.ipdst
|
|
95
|
+
)
|
|
96
|
+
if self.payload:
|
|
97
|
+
new_layer.payload = self.payload.copy() if hasattr(self.payload, 'copy') else self.payload
|
|
98
|
+
if self._raw_payload:
|
|
99
|
+
new_layer._raw_payload = self._raw_payload
|
|
100
|
+
return new_layer
|
|
101
|
+
|
|
102
|
+
def _show_fields(self) -> list:
|
|
103
|
+
return [
|
|
104
|
+
f"hwtype={self.hwtype}",
|
|
105
|
+
f"ptype=0x{self.ptype:04x}",
|
|
106
|
+
f"maclen={self.maclen}",
|
|
107
|
+
f"plen={self.plen}",
|
|
108
|
+
f"opcode={self.opcode}",
|
|
109
|
+
f"macsrc={self.macsrc}",
|
|
110
|
+
f"ipsrc={self.ipsrc}",
|
|
111
|
+
f"macdst={self.macdst}",
|
|
112
|
+
f"ipdst={self.ipdst}"
|
|
113
|
+
]
|
|
114
|
+
|
|
115
|
+
"""
|
|
116
|
+
Arp Parser (separate from the builder)
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
class ArpParser:
|
|
120
|
+
|
|
121
|
+
@staticmethod
|
|
122
|
+
def load_as_arp_layer(raw_packet,Alr=0,verbose=False):
|
|
123
|
+
if type(raw_packet) is not list:
|
|
124
|
+
raw_packet = [raw_packet]
|
|
125
|
+
if hasattr(raw_packet[0], 'build') and type(raw_packet[0]) is not bytes:
|
|
126
|
+
raw_packet[0] = raw_packet[0].build()
|
|
127
|
+
|
|
128
|
+
if len(raw_packet[0]) < 28:
|
|
129
|
+
LLogger.error(error_code=ErrorCode.INVALID_DATA_LENGTH,message="Arp required header is 28 bytes")
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
ArpHeader = raw_packet[0]
|
|
133
|
+
|
|
134
|
+
hwtype, ptype, maclen, plen, opcode = struct.unpack('!HHBBH', ArpHeader[:8])
|
|
135
|
+
offset = 8
|
|
136
|
+
sender_mac = ArpHeader[offset:offset + 6]
|
|
137
|
+
offset += 6
|
|
138
|
+
sender_mac_str = ':'.join(f'{b:02x}' for b in sender_mac)
|
|
139
|
+
sender_ip = ArpHeader[offset:offset + 4]
|
|
140
|
+
offset += 4
|
|
141
|
+
sender_ip_str = inet_ntoa(sender_ip)
|
|
142
|
+
target_mac = ArpHeader[offset:offset + 6]
|
|
143
|
+
offset += 6
|
|
144
|
+
target_mac_str = ':'.join(f'{b:02x}' for b in target_mac)
|
|
145
|
+
target_ip = ArpHeader[offset:offset + 4]
|
|
146
|
+
target_ip_str = inet_ntoa(target_ip)
|
|
147
|
+
payload = ArpHeader[28:]
|
|
148
|
+
Lenght = len(ArpHeader[:28])
|
|
149
|
+
Total = len(payload) + Lenght
|
|
150
|
+
if opcode == 1:
|
|
151
|
+
opcode_e = "(who-has)"
|
|
152
|
+
elif opcode == 2:
|
|
153
|
+
opcode_e = "(is-at)"
|
|
154
|
+
elif opcode == 3:
|
|
155
|
+
opcode_e = "(RARP-req)"
|
|
156
|
+
elif opcode == 4:
|
|
157
|
+
opcode_e = "(RARP-rep)"
|
|
158
|
+
elif opcode == 5:
|
|
159
|
+
opcode_e = "(Dyn-RARP-req)"
|
|
160
|
+
elif opcode == 6:
|
|
161
|
+
opcode_e = "(Dyn-RARP-rep)"
|
|
162
|
+
elif opcode == 7:
|
|
163
|
+
opcode_e = "(Dyn-RARP-err)"
|
|
164
|
+
elif opcode == 8:
|
|
165
|
+
opcode_e = "(In-ARP-req)"
|
|
166
|
+
elif opcode == 9:
|
|
167
|
+
opcode_e = "(In-ARP-rep)"
|
|
168
|
+
else:
|
|
169
|
+
opcode_e = "(Unknown)"
|
|
170
|
+
|
|
171
|
+
if verbose:
|
|
172
|
+
print(f"\n{BOLD}ARP LAYER : {RESET}Len({PURPLE}{Lenght}{RESET}) Total Len({PURPLE}{Total}{RESET}) >")
|
|
173
|
+
print(f' {BLUE}HWTYPE:{CYAN} {hwtype} {HWTYPES.get(hwtype,'Unknown')}')
|
|
174
|
+
print(f' {BLUE}PTYPE:{CYAN} {hex(ptype)} {ETHERTYPE.get(ptype,'Unknown')}')
|
|
175
|
+
print(f' {BLUE}MACLEN:{CYAN} {maclen}')
|
|
176
|
+
print(f' {BLUE}PLEN:{CYAN} {plen}')
|
|
177
|
+
print(f' {BLUE}OPCODE:{CYAN} {opcode} {opcode_e}')
|
|
178
|
+
print(f' {BLUE}MAC SRC:{CYAN} {sender_mac_str} ({'Multicast' if sender_mac_str[:2] in MC else OUI_MAP.get(sender_mac_str.replace(":", "")[:6],'?')})')
|
|
179
|
+
print(f' {BLUE}IP SRC:{CYAN} {sender_ip_str}')
|
|
180
|
+
print(f' {BLUE}MAC DST:{CYAN} {target_mac_str} ({'Multicast' if target_mac_str[:2] in MC else OUI_MAP.get(target_mac_str.replace(":", "")[:6],'?')})')
|
|
181
|
+
print(f' {BLUE}IP DST:{CYAN} {target_ip_str}{RESET}')
|
|
182
|
+
|
|
183
|
+
if len(payload) > 0:
|
|
184
|
+
from .Raw import RawParser
|
|
185
|
+
RawParser.load_as_Raw_layer(payload,verbose=verbose)
|
|
186
|
+
|
|
187
|
+
arp = ARP(
|
|
188
|
+
hwtype=hwtype,
|
|
189
|
+
ptype=ptype,
|
|
190
|
+
maclen=maclen,
|
|
191
|
+
plen=plen,
|
|
192
|
+
opcode=opcode,
|
|
193
|
+
macsrc=sender_mac_str,
|
|
194
|
+
macdst=target_mac_str,
|
|
195
|
+
ipsrc=sender_ip_str,
|
|
196
|
+
ipdst=target_ip_str
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
return arp
|
|
200
|
+
|
|
201
|
+
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Union, Any
|
|
6
|
+
import copy
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BaseLayer:
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
self.payload: Optional['BaseLayer'] = None
|
|
13
|
+
|
|
14
|
+
self._raw_payload: Optional[bytes] = None
|
|
15
|
+
|
|
16
|
+
def __truediv__(self, other: Union['BaseLayer', bytes]) -> 'BaseLayer':
|
|
17
|
+
new_layer = self.copy()
|
|
18
|
+
|
|
19
|
+
new_layer.set_payload(other)
|
|
20
|
+
return new_layer
|
|
21
|
+
|
|
22
|
+
def __bool__(self) -> bool:
|
|
23
|
+
return True
|
|
24
|
+
|
|
25
|
+
def __rtruediv__(self, other: Union['BaseLayer', bytes]) -> 'BaseLayer':
|
|
26
|
+
if isinstance(other, BaseLayer):
|
|
27
|
+
other.set_payload(self)
|
|
28
|
+
return other
|
|
29
|
+
elif isinstance(other, bytes):
|
|
30
|
+
from .Raw import RawLayer
|
|
31
|
+
raw = RawLayer(other)
|
|
32
|
+
raw.set_payload(self)
|
|
33
|
+
return raw
|
|
34
|
+
else:
|
|
35
|
+
raise TypeError(f"Cannot divide {type(other)} and {type(self)}")
|
|
36
|
+
|
|
37
|
+
def set_payload(self, payload: Union['BaseLayer', bytes]) -> None:
|
|
38
|
+
if isinstance(payload, BaseLayer):
|
|
39
|
+
if self.payload is not None:
|
|
40
|
+
last = self.payload
|
|
41
|
+
while last.payload is not None:
|
|
42
|
+
last = last.payload
|
|
43
|
+
last.payload = payload
|
|
44
|
+
else:
|
|
45
|
+
self.payload = payload
|
|
46
|
+
elif isinstance(payload, bytes):
|
|
47
|
+
self.payload = None
|
|
48
|
+
self._raw_payload = payload
|
|
49
|
+
else:
|
|
50
|
+
raise TypeError(f"Payload must be BaseLayer or bytes, got {type(payload)}")
|
|
51
|
+
|
|
52
|
+
def get_payload_bytes(self) -> bytes:
|
|
53
|
+
if self.payload is not None:
|
|
54
|
+
return self.payload.build()
|
|
55
|
+
elif self._raw_payload is not None:
|
|
56
|
+
return self._raw_payload
|
|
57
|
+
else:
|
|
58
|
+
return b''
|
|
59
|
+
|
|
60
|
+
def __getitem__(self, key):
|
|
61
|
+
if isinstance(key, tuple):
|
|
62
|
+
if len(key) == 2 and isinstance(key[1], int):
|
|
63
|
+
return self._get_nth_layer(key[0], key[1])
|
|
64
|
+
|
|
65
|
+
if isinstance(key, slice):
|
|
66
|
+
if key.stop is None:
|
|
67
|
+
return self._get_all_layers(key.start)
|
|
68
|
+
else:
|
|
69
|
+
return self._get_nth_layer(key.start, key.stop)
|
|
70
|
+
|
|
71
|
+
return self._get_nth_layer(key, 1)
|
|
72
|
+
|
|
73
|
+
def _get_nth_layer(self, layer_type, index):
|
|
74
|
+
if index == 0:
|
|
75
|
+
raise ValueError("Index must be non-zero")
|
|
76
|
+
|
|
77
|
+
if index < 0:
|
|
78
|
+
all_layers = self._get_all_layers(layer_type)
|
|
79
|
+
if not all_layers:
|
|
80
|
+
raise KeyError(f"Layer {layer_type.__name__} not found")
|
|
81
|
+
return all_layers[index]
|
|
82
|
+
|
|
83
|
+
current = self
|
|
84
|
+
found = 0
|
|
85
|
+
while current:
|
|
86
|
+
if isinstance(current, layer_type):
|
|
87
|
+
found += 1
|
|
88
|
+
if found == index:
|
|
89
|
+
return current
|
|
90
|
+
current = current.payload
|
|
91
|
+
|
|
92
|
+
if found == 0:
|
|
93
|
+
raise KeyError(f"Layer {layer_type.__name__} not found")
|
|
94
|
+
raise IndexError(f"Only {found} layers found, requested {index}")
|
|
95
|
+
|
|
96
|
+
def _get_all_layers(self, layer_type):
|
|
97
|
+
results = []
|
|
98
|
+
current = self
|
|
99
|
+
while current:
|
|
100
|
+
if isinstance(current, layer_type):
|
|
101
|
+
results.append(current)
|
|
102
|
+
current = current.payload
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
def __contains__(self, layer_type):
|
|
106
|
+
try:
|
|
107
|
+
self._get_nth_layer(layer_type, 1)
|
|
108
|
+
return True
|
|
109
|
+
except (KeyError, IndexError):
|
|
110
|
+
return False
|
|
111
|
+
|
|
112
|
+
def build(self) -> bytes:
|
|
113
|
+
raise NotImplementedError("Subclasses must implement build()")
|
|
114
|
+
|
|
115
|
+
def copy(self) -> 'BaseLayer':
|
|
116
|
+
return copy.copy(self)
|
|
117
|
+
|
|
118
|
+
def __bytes__(self) -> bytes:
|
|
119
|
+
return self.build()
|
|
120
|
+
|
|
121
|
+
def __len__(self):
|
|
122
|
+
return len(self.build())
|
|
123
|
+
|
|
124
|
+
def __repr__(self) -> str:
|
|
125
|
+
return f"<{self.__class__.__name__}>"
|
|
126
|
+
|
|
127
|
+
def show(self, indent: int = 0) -> None:
|
|
128
|
+
from .Decoration.Colors import BOLD, BLUE, PURPLE, RESET
|
|
129
|
+
|
|
130
|
+
pad = " " * indent
|
|
131
|
+
print(f"{pad}{BOLD}--- [ {PURPLE}{self.__class__.__name__}{PURPLE}{RESET}{BOLD} ] ---{RESET}")
|
|
132
|
+
args = self._show_fields()
|
|
133
|
+
for arg in args:
|
|
134
|
+
if arg is not None:
|
|
135
|
+
print(f"{pad} {arg}")
|
|
136
|
+
|
|
137
|
+
if self.payload:
|
|
138
|
+
print(f"{pad} {BLUE}\\{RESET}")
|
|
139
|
+
self.payload.show(indent + 4)
|
|
140
|
+
|
|
141
|
+
def _show_fields(self) -> str:
|
|
142
|
+
return str(self)
|
|
143
|
+
|
|
144
|
+
def _show_fields_list(self):
|
|
145
|
+
return [str(self)]
|