Coverage for an_website / host_info / host_info.py: 81.633%

49 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-04-24 17:35 +0000

1# This program is free software: you can redistribute it and/or modify 

2# it under the terms of the GNU Affero General Public License as 

3# published by the Free Software Foundation, either version 3 of the 

4# License, or (at your option) any later version. 

5# 

6# This program is distributed in the hope that it will be useful, 

7# but WITHOUT ANY WARRANTY; without even the implied warranty of 

8# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

9# GNU Affero General Public License for more details. 

10# 

11# You should have received a copy of the GNU Affero General Public License 

12# along with this program. If not, see <https://www.gnu.org/licenses/>. 

13 

14""" 

15The host info page of the website. 

16 

17Only to inform, not to brag. 

18""" 

19 

20import shutil 

21import sys 

22from collections.abc import Mapping 

23from ctypes import c_char 

24from multiprocessing import Array 

25from typing import Final 

26 

27import regex 

28from tornado.web import HTTPError as HTTPEwwow 

29 

30from .. import CONTAINERIZED, DIR as ROOT_DIR, NAME, traversable_to_file 

31from ..utils.request_handler import HTMLRequestHandler 

32from ..utils.utils import ModuleInfo, PageInfo, run 

33 

34SCREENFETCH: Final = ( 

35 shutil.which("bash") or "bash", 

36 traversable_to_file(ROOT_DIR / "vendored" / "screenfetch").as_posix(), 

37) 

38UWUFETCH_PATH: Final = shutil.which("uwufetch") 

39ENV: Final[Mapping[str, str]] = { 

40 "USER": NAME, 

41 "SHELL": ( 

42 f"{sys.implementation.name}{'.'.join(str(_) for _ in sys.version_info[:3])}" 

43 ), 

44} 

45 

46 

47def get_module_info() -> ModuleInfo: 

48 """Create and return the ModuleInfo for this module.""" 

49 return ModuleInfo( 

50 handlers=( 

51 (r"/host-info", HostInfo), 

52 (r"/host-info/uwu", UwUHostInfo), 

53 ), 

54 name="Host-Informationen", 

55 short_name="Host-Info", 

56 description="Informationen über den Host-Server dieser Webseite", 

57 path="/host-info", 

58 aliases=("/server-info",), 

59 sub_pages=( 

60 PageInfo( 

61 name="Howost-Infowmationyen", 

62 short_name="Howost-Infow", 

63 description=( 

64 "Infowmationyen übew den Howost-Sewvew diesew W-Webseite" 

65 ), 

66 path="/host-info/uwu", 

67 keywords=("UWU",), 

68 hidden=CONTAINERIZED or not UWUFETCH_PATH, 

69 ), 

70 ), 

71 keywords=("Host", "Informationen", "Screenfetch"), 

72 hidden=CONTAINERIZED, 

73 ) 

74 

75 

76def minify_ansi_art(string: bytes) -> bytes: 

77 """Minify an ANSI art string.""" 

78 return regex.sub( 

79 rb"(?m)\s+\x1B\[0m$", b"\x1B[0m", string 

80 ) # for arch: 1059 → 898 

81 

82 

83class HostInfo(HTMLRequestHandler): 

84 """The request handler for the host info page.""" 

85 

86 RATELIMIT_GET_LIMIT = 1 

87 

88 SCREENFETCH_CACHE = Array(c_char, 1024**2) 

89 

90 async def get(self, *, head: bool = False) -> None: 

91 """ 

92 Handle GET requests to the host info page. 

93 

94 Use screenFetch to generate the page. 

95 """ 

96 if head: 

97 return 

98 

99 logo = self.SCREENFETCH_CACHE.value 

100 

101 if not logo: 

102 logo = minify_ansi_art((await run(*SCREENFETCH, "-L"))[1]) 

103 self.SCREENFETCH_CACHE.value = logo 

104 

105 screenfetch_bytes = (await run(*SCREENFETCH, "-n", env=ENV))[1] 

106 

107 if self.content_type == "text/plain": 

108 return await self.finish(logo + b"\n\n" + screenfetch_bytes) 

109 

110 await self.render( 

111 "ansi2html.html", 

112 ansi=[ 

113 logo.decode("UTF-8"), 

114 screenfetch_bytes.decode("UTF-8"), 

115 ], 

116 powered_by="https://github.com/KittyKatt/screenFetch", 

117 powered_by_name="screenFetch", 

118 ) 

119 

120 

121class UwUHostInfo(HTMLRequestHandler): 

122 """The wequest handwew fow the coowew host info page.""" 

123 

124 RATELIMIT_GET_LIMIT = 1 

125 

126 async def get(self, *, head: bool = False) -> None: 

127 """ 

128 Handwe the GET wequests to coowew the host info page. 

129 

130 Use UwUFetch to genyewate the page. 

131 """ 

132 cache_enabwed = int( 

133 head or not self.get_bool_argument("cache_disabled", False) 

134 ) 

135 

136 if UWUFETCH_PATH: 

137 wetuwn_code, uwufetch_bytes, _ = await run( 

138 UWUFETCH_PATH, 

139 "-w", 

140 env={"UWUFETCH_CACHE_ENABLED": str(cache_enabwed), **ENV}, 

141 ) 

142 else: 

143 wetuwn_code, uwufetch_bytes = 127, b"" 

144 

145 if wetuwn_code == 127: 

146 raise HTTPEwwow( 

147 503, 

148 reason="This sewvew h-hasn't instawwed UwUFetch", 

149 ) 

150 

151 if wetuwn_code: 

152 raise HTTPEwwow( 

153 500, 

154 reason=f"UwUFetch has exited with wetuwn code {wetuwn_code}", 

155 ) 

156 

157 if head: 

158 return 

159 

160 if self.content_type == "text/plain": 

161 return await self.finish(uwufetch_bytes) 

162 

163 uwufetch = uwufetch_bytes.decode("UTF-8") 

164 await self.render( 

165 "ansi2html.html", 

166 ansi=uwufetch.split("\n\n"), 

167 powered_by="https://github.com/ad-oliviero/uwufetch", 

168 powered_by_name="UwUFetch", 

169 )