jee122 commited on
Commit
bcf81dd
·
verified ·
1 Parent(s): 6e661c2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +63 -94
app.py CHANGED
@@ -5,7 +5,8 @@ import re
5
  from flask import Flask, render_template_string, request, session, redirect, url_for, send_file, Response
6
 
7
  app = Flask(__name__)
8
- app.secret_key = os.urandom(32)
 
9
 
10
  # --- IDENTITY & CREDENTIALS ---
11
  OWNER_NAME = "WhyLaugh404"
@@ -24,52 +25,46 @@ ACCESS_LEVELS = {
24
  "owner": ["sherlock", "maigret", "socialscan", "holehe", "phoneinfoga", "twint", "exiftool", "ghunt", "cloud_enum"]
25
  }
26
 
27
- # --- REGEX UNTUK BERSIHIN KODE WARNA TERMINAL ---
28
  ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
29
 
30
- # --- STYLING: J.S.T VANGUARD THEME ---
31
  CSS = """
32
  :root { --bg: #000000; --panel: #050505; --accent: #00ff00; --accent-glow: #00ff0044; --text: #00ff00; --border: #111; --danger: #ff003c; }
33
- body { background: var(--bg); color: var(--text); font-family: 'JetBrains Mono', 'Courier New', monospace; margin: 0; padding: 0; text-shadow: 0 0 5px var(--accent-glow); }
34
-
35
- /* Custom Scrollbar */
36
- ::-webkit-scrollbar { width: 8px; }
37
- ::-webkit-scrollbar-track { background: var(--bg); border-left: 1px solid var(--border); }
38
- ::-webkit-scrollbar-thumb { background: var(--border); border: 1px solid var(--accent); }
39
- ::-webkit-scrollbar-thumb:hover { background: var(--accent); }
40
-
41
- /* CRT Scanline Effect */
42
- body::before { content: " "; display: block; position: fixed; top: 0; left: 0; bottom: 0; right: 0; background: linear-gradient(rgba(18, 16, 16, 0) 50%, rgba(0, 0, 0, 0.25) 50%), linear-gradient(90deg, rgba(255, 0, 0, 0.06), rgba(0, 255, 0, 0.02), rgba(0, 0, 255, 0.06)); z-index: 2; background-size: 100% 2px, 3px 100%; pointer-events: none; }
43
-
44
- .login-screen { display: flex; align-items: center; justify-content: center; height: 100vh; flex-direction: column; position: relative; z-index: 5; }
45
- .jst-brand { font-size: 2.5em; font-weight: bold; color: var(--text); letter-spacing: 10px; margin-bottom: 5px; }
46
- .login-card { background: var(--panel); border: 1px solid var(--accent); padding: 40px; width: 320px; text-align: center; box-shadow: 0 0 20px var(--accent-glow); }
47
-
48
- .header { background: var(--panel); border-bottom: 1px solid var(--accent); padding: 20px; text-align: center; position: relative; z-index: 5; }
49
- .mrx-logo { width: 90px; height: 90px; border-radius: 50%; border: 2px solid var(--accent); margin-bottom: 10px; box-shadow: 0 0 15px var(--accent); filter: grayscale(100%) contrast(120%); }
50
- .container { max-width: 1400px; margin: 30px auto; padding: 0 20px; position: relative; z-index: 5; }
51
- .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 30px; }
52
- .card { background: var(--panel); border: 1px solid #222; padding: 20px; transition: 0.3s; }
53
- .card:hover { border-color: var(--accent); box-shadow: 0 0 15px var(--accent-glow); }
54
- .card h3 { font-size: 0.8em; border-bottom: 1px dashed var(--accent); padding-bottom: 8px; margin-bottom: 15px; letter-spacing: 2px; }
55
-
56
- input { background: transparent; border: 1px solid #333; color: var(--text); padding: 12px; width: 100%; box-sizing: border-box; outline: none; margin-bottom: 10px; font-family: inherit; }
57
- input:focus { border-color: var(--accent); background: #020202; }
58
- button { background: transparent; border: 1px solid var(--accent); color: var(--accent); padding: 10px; width: 100%; cursor: pointer; font-weight: bold; letter-spacing: 2px; transition: 0.2s; }
59
  button:hover:not(:disabled) { background: var(--accent); color: #000; }
60
- button:disabled { border-color: #333; color: #333; cursor: not-allowed; text-shadow: none; }
61
 
62
  .console-box { background: #000; border: 1px solid #222; margin-top: 15px; display: none; flex-direction: column; }
63
- .console-header { background: #050505; padding: 8px 12px; font-size: 0.7em; display: flex; justify-content: space-between; border-bottom: 1px solid #222; }
64
- .console-body { padding: 15px; height: 350px; overflow-y: auto; font-size: 0.8em; white-space: pre-wrap; line-height: 1.5; color: #cfc; }
65
- .dl-btn { color: var(--accent); text-decoration: none; border: 1px solid var(--accent); padding: 2px 10px; display: none; }
66
- .dl-btn:hover { background: var(--accent); color: #000; }
67
  .blinking-cursor { animation: blink 1s step-end infinite; }
68
  @keyframes blink { 50% { opacity: 0; } }
69
  """
70
 
71
- # --- SERVER LOGIC ---
72
-
73
  @app.route('/', methods=['GET', 'POST'])
74
  def entry():
75
  if request.method == 'POST':
@@ -78,21 +73,18 @@ def entry():
78
  if p == val:
79
  session['role'] = role
80
  return redirect(url_for('entry'))
81
- return "<body style='background:#000; color:red; text-align:center; padding-top:10vh; font-family:monospace; font-size:2em;'>[!] INTRUSION DETECTED <br> ACCESS DENIED</body>"
82
 
83
  if 'role' in session:
84
  return render_template_string(T_DASHBOARD, css=CSS, owner=OWNER_NAME, team=TEAM_NAME,
85
  role=session['role'], allowed=ACCESS_LEVELS[session['role']], mrx_url=MRX_LOGO)
86
-
87
  return render_template_string(T_LOGIN, css=CSS, team=TEAM_NAME, owner=OWNER_NAME)
88
 
89
  @app.route('/stream/<tool_id>')
90
  def stream(tool_id):
91
  if 'role' not in session or tool_id not in ACCESS_LEVELS[session['role']]:
92
  return Response("Unauthorized", status=403)
93
-
94
  target = request.args.get('target', '').strip()
95
-
96
  def generate():
97
  cmds = {
98
  "sherlock": f"sherlock {target} --timeout 5",
@@ -105,55 +97,44 @@ def stream(tool_id):
105
  "ghunt": f"ghunt email {target}",
106
  "cloud_enum": f"python3 /home/user/cloud_enum/cloud_enum.py -k {target}"
107
  }
108
-
109
  cmd = cmds.get(tool_id)
110
  report_file = f"JST_REPORT_{tool_id.upper()}_{target.replace('.', '_')}.txt"
111
-
112
- # FIX: Pisahin string biar Python 3.10 gak ngambek kena backslash di dalem f-string json
113
- init_msg = f"> Initiating protocol: {tool_id.upper()}\n> Target: {target}\n> Bypassing nodes...\n\n"
114
  yield f"data: {json.dumps({'line': init_msg})}\n\n"
115
-
116
  process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True)
117
-
118
  full_log = ""
119
  for line in process.stdout:
120
- # BERSIHKAN KODE WARNA ANSI
121
  clean_line = ansi_escape.sub('', line)
122
  full_log += clean_line
123
  yield f"data: {json.dumps({'line': clean_line})}\n\n"
124
-
125
  process.wait()
126
-
127
- # FIX: Gunakan \n biasa buat write ke file biar turun baris beneran di TXT
128
  with open(report_file, "w") as f:
129
- f.write(f"--- {TEAM_NAME} SECURITY REPORT ---\nOPERATOR: {OWNER_NAME}\nTOOL: {tool_id.upper()}\nTARGET: {target}\n\n{full_log}")
130
-
131
  yield f"data: {json.dumps({'done': True, 'file': report_file})}\n\n"
132
-
133
  return Response(generate(), mimetype='text/event-stream')
134
 
135
  @app.route('/dl/<filename>')
136
  def dl(filename):
137
  if filename.startswith("JST_REPORT_") and os.path.exists(filename):
138
  return send_file(filename, as_attachment=True)
139
- return "Error: File Not Found", 404
140
 
141
- @app.route('/exit')
142
- def exit_node():
143
  session.clear()
144
  return redirect(url_for('entry'))
145
 
146
- # --- HTML TEMPLATES ---
147
-
148
  T_LOGIN = """
149
- <!DOCTYPE html><html><head><title>{{team}} | AUTH</title><style>{{css}}</style></head>
 
 
150
  <body class="login-screen">
151
  <div class="jst-brand">{{team}}</div>
152
- <div style="color:#555; letter-spacing:5px; margin-bottom:30px;">[ CENTRAL NODE ]</div>
153
  <div class="login-card">
154
- <div style="font-size:0.8em; margin-bottom:20px;">REQUIRE IDENTIFICATION</div>
155
  <form method="post">
156
- <input type="password" name="p" placeholder="ENTER PASSPHRASE" required autofocus>
157
  <button type="submit">AUTHENTICATE</button>
158
  </form>
159
  </div>
@@ -161,64 +142,54 @@ T_LOGIN = """
161
  """
162
 
163
  T_DASHBOARD = """
164
- <!DOCTYPE html><html><head><title>{{team}} CONSOLE</title><style>{{css}}</style></head><body>
 
 
165
  <div class="header">
166
- <img src="{{mrx_url}}" class="mrx-logo">
167
- <div style="font-size:1.5em; font-weight:bold; letter-spacing:5px;">{{team}} CONSOLE</div>
168
- <div style="font-size:0.7em; margin-top:10px; color:#666;">OP: {{owner}} | STATUS: SECURE | LVL: {{role.upper()}}</div>
 
 
 
 
 
169
  </div>
170
-
171
  <div class="container">
172
  <div class="grid">
173
  {% for t_id in allowed %}
174
  <div class="card">
175
- <h3>>> MODULE: {{t_id.upper()}}</h3>
176
  <form onsubmit="runTool(event, '{{t_id}}')">
177
- <input type="text" id="target-{{t_id}}" placeholder="Target parameter..." required>
178
- <button type="submit" id="btn-{{t_id}}">START_{{t_id.upper()}}</button>
179
  </form>
180
-
181
  <div id="sess-{{t_id}}" class="console-box">
182
- <div class="console-header">
183
- <span>LIVE_LOG: {{t_id.upper()}}</span>
184
- <a href="#" id="dl-{{t_id}}" class="dl-btn">SAVE_DUMP</a>
185
- </div>
186
- <div class="console-body">
187
- <span id="out-{{t_id}}"></span><span id="cursor-{{t_id}}" class="blinking-cursor">_</span>
188
- </div>
189
  </div>
190
  </div>
191
  {% endfor %}
192
  </div>
193
- <br><center><a href="/exit" style="color:#333; text-decoration:none; font-size:0.8em; letter-spacing:2px;">[ CLOSE CONNECTION ]</a></center>
194
  </div>
195
-
196
  <script>
197
- let currentEventSources = {};
198
-
199
  function runTool(e, id) {
200
  e.preventDefault();
201
  const val = document.getElementById('target-'+id).value;
202
- if(!val) return;
203
-
204
  const out = document.getElementById('out-'+id);
205
  const sess = document.getElementById('sess-'+id);
206
  const dl = document.getElementById('dl-'+id);
207
  const btn = document.getElementById('btn-'+id);
208
  const cursor = document.getElementById('cursor-'+id);
209
 
210
- if(currentEventSources[id]) { currentEventSources[id].close(); }
211
-
212
  sess.style.display = 'flex';
213
  out.innerHTML = "";
214
  dl.style.display = 'none';
215
  btn.disabled = true;
216
- btn.innerText = "EXECUTING...";
217
  cursor.style.display = "inline";
218
 
219
  const source = new EventSource(`/stream/${id}?target=${val}`);
220
- currentEventSources[id] = source;
221
-
222
  source.onmessage = function(event) {
223
  const data = JSON.parse(event.data);
224
  if(data.line) {
@@ -228,19 +199,17 @@ function runTool(e, id) {
228
  if(data.done) {
229
  source.close();
230
  btn.disabled = false;
231
- btn.innerText = "START_" + id.upper();
232
  dl.href = "/dl/" + data.file;
233
  dl.style.display = 'inline-block';
234
  cursor.style.display = "none";
235
  }
236
  };
237
-
238
  source.onerror = function() {
239
  source.close();
240
  btn.disabled = false;
241
- btn.innerText = "START_" + id.upper();
242
- out.innerHTML += "\\n[!] ERR: CONNECTION LOST OR TIMEOUT";
243
- cursor.style.display = "none";
244
  };
245
  }
246
  </script>
 
5
  from flask import Flask, render_template_string, request, session, redirect, url_for, send_file, Response
6
 
7
  app = Flask(__name__)
8
+ # Secret key statis biar login gak mental-mental
9
+ app.secret_key = "JST_STABLE_NODE_KEY_404_ZIE"
10
 
11
  # --- IDENTITY & CREDENTIALS ---
12
  OWNER_NAME = "WhyLaugh404"
 
25
  "owner": ["sherlock", "maigret", "socialscan", "holehe", "phoneinfoga", "twint", "exiftool", "ghunt", "cloud_enum"]
26
  }
27
 
 
28
  ansi_escape = re.compile(r'\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])')
29
 
30
+ # --- STYLING: RESPONSIVE J.S.T THEME ---
31
  CSS = """
32
  :root { --bg: #000000; --panel: #050505; --accent: #00ff00; --accent-glow: #00ff0044; --text: #00ff00; --border: #111; --danger: #ff003c; }
33
+ body { background: var(--bg); color: var(--text); font-family: 'JetBrains Mono', monospace; margin: 0; padding: 0; text-shadow: 0 0 5px var(--accent-glow); overflow-x: hidden; }
34
+
35
+ .login-screen { display: flex; align-items: center; justify-content: center; min-height: 100vh; flex-direction: column; padding: 20px; }
36
+ .jst-brand { font-size: 2em; font-weight: bold; letter-spacing: 5px; text-align: center; }
37
+ .login-card { background: var(--panel); border: 1px solid var(--accent); padding: 30px; width: 100%; max-width: 350px; box-sizing: border-box; box-shadow: 0 0 20px var(--accent-glow); }
38
+
39
+ .header { background: var(--panel); border-bottom: 1px solid var(--accent); padding: 15px; position: relative; display: flex; align-items: center; justify-content: space-between; }
40
+ .header-info { display: flex; align-items: center; gap: 15px; }
41
+ .mrx-logo { width: 50px; height: 50px; border-radius: 50%; border: 1px solid var(--accent); }
42
+ .logout-btn { color: var(--danger); text-decoration: none; border: 1px solid var(--danger); padding: 5px 12px; font-size: 0.7em; letter-spacing: 1px; font-weight: bold; transition: 0.3s; }
43
+ .logout-btn:hover { background: var(--danger); color: #fff; }
44
+
45
+ .container { width: 100%; max-width: 1400px; margin: 20px auto; padding: 0 15px; box-sizing: border-box; }
46
+ .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 20px; }
47
+
48
+ @media (max-width: 600px) {
49
+ .header { flex-direction: column; gap: 10px; text-align: center; }
50
+ .header-info { flex-direction: column; gap: 5px; }
51
+ .grid { grid-template-columns: 1fr; }
52
+ }
53
+
54
+ .card { background: var(--panel); border: 1px solid #222; padding: 15px; }
55
+ .card:hover { border-color: var(--accent); }
56
+ input { background: transparent; border: 1px solid #333; color: var(--text); padding: 12px; width: 100%; box-sizing: border-box; margin-bottom: 10px; font-family: inherit; outline: none; }
57
+ button { background: transparent; border: 1px solid var(--accent); color: var(--accent); padding: 10px; width: 100%; cursor: pointer; font-weight: bold; }
 
58
  button:hover:not(:disabled) { background: var(--accent); color: #000; }
 
59
 
60
  .console-box { background: #000; border: 1px solid #222; margin-top: 15px; display: none; flex-direction: column; }
61
+ .console-header { background: #050505; padding: 8px; font-size: 0.7em; display: flex; justify-content: space-between; border-bottom: 1px solid #222; }
62
+ .console-body { padding: 10px; height: 300px; overflow-y: auto; font-size: 0.75em; white-space: pre-wrap; color: #cfc; }
63
+ .dl-btn { color: var(--accent); text-decoration: none; border: 1px solid var(--accent); padding: 2px 8px; font-size: 0.9em; display: none; }
 
64
  .blinking-cursor { animation: blink 1s step-end infinite; }
65
  @keyframes blink { 50% { opacity: 0; } }
66
  """
67
 
 
 
68
  @app.route('/', methods=['GET', 'POST'])
69
  def entry():
70
  if request.method == 'POST':
 
73
  if p == val:
74
  session['role'] = role
75
  return redirect(url_for('entry'))
76
+ return "<body style='background:#000; color:red; text-align:center; padding-top:10vh; font-family:monospace;'>[!] ACCESS DENIED</body>"
77
 
78
  if 'role' in session:
79
  return render_template_string(T_DASHBOARD, css=CSS, owner=OWNER_NAME, team=TEAM_NAME,
80
  role=session['role'], allowed=ACCESS_LEVELS[session['role']], mrx_url=MRX_LOGO)
 
81
  return render_template_string(T_LOGIN, css=CSS, team=TEAM_NAME, owner=OWNER_NAME)
82
 
83
  @app.route('/stream/<tool_id>')
84
  def stream(tool_id):
85
  if 'role' not in session or tool_id not in ACCESS_LEVELS[session['role']]:
86
  return Response("Unauthorized", status=403)
 
87
  target = request.args.get('target', '').strip()
 
88
  def generate():
89
  cmds = {
90
  "sherlock": f"sherlock {target} --timeout 5",
 
97
  "ghunt": f"ghunt email {target}",
98
  "cloud_enum": f"python3 /home/user/cloud_enum/cloud_enum.py -k {target}"
99
  }
 
100
  cmd = cmds.get(tool_id)
101
  report_file = f"JST_REPORT_{tool_id.upper()}_{target.replace('.', '_')}.txt"
102
+ init_msg = f"> Initializing {tool_id.upper()} protocol...\n> Target: {target}\n\n"
 
 
103
  yield f"data: {json.dumps({'line': init_msg})}\n\n"
 
104
  process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True, bufsize=1, universal_newlines=True)
 
105
  full_log = ""
106
  for line in process.stdout:
 
107
  clean_line = ansi_escape.sub('', line)
108
  full_log += clean_line
109
  yield f"data: {json.dumps({'line': clean_line})}\n\n"
 
110
  process.wait()
 
 
111
  with open(report_file, "w") as f:
112
+ f.write(f"--- {TEAM_NAME} REPORT ---\nOP: {OWNER_NAME}\nTOOL: {tool_id.upper()}\n\n{full_log}")
 
113
  yield f"data: {json.dumps({'done': True, 'file': report_file})}\n\n"
 
114
  return Response(generate(), mimetype='text/event-stream')
115
 
116
  @app.route('/dl/<filename>')
117
  def dl(filename):
118
  if filename.startswith("JST_REPORT_") and os.path.exists(filename):
119
  return send_file(filename, as_attachment=True)
120
+ return "Error", 404
121
 
122
+ @app.route('/logout')
123
+ def logout():
124
  session.clear()
125
  return redirect(url_for('entry'))
126
 
127
+ # --- TEMPLATES ---
 
128
  T_LOGIN = """
129
+ <!DOCTYPE html><html><head>
130
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
131
+ <title>{{team}} | AUTH</title><style>{{css}}</style></head>
132
  <body class="login-screen">
133
  <div class="jst-brand">{{team}}</div>
134
+ <div style="color:#444; letter-spacing:3px; margin-bottom:20px; font-size:0.8em;">[ CENTRAL NODE ]</div>
135
  <div class="login-card">
 
136
  <form method="post">
137
+ <input type="password" name="p" placeholder="PASSPHRASE" required autofocus>
138
  <button type="submit">AUTHENTICATE</button>
139
  </form>
140
  </div>
 
142
  """
143
 
144
  T_DASHBOARD = """
145
+ <!DOCTYPE html><html><head>
146
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
147
+ <title>{{team}} CONSOLE</title><style>{{css}}</style></head><body>
148
  <div class="header">
149
+ <div class="header-info">
150
+ <img src="{{mrx_url}}" class="mrx-logo">
151
+ <div>
152
+ <div style="font-weight:bold; letter-spacing:2px; font-size:1.1em;">{{team}} CONSOLE</div>
153
+ <div style="font-size:0.6em; color:#555;">OPERATOR: {{owner}} | LVL: {{role.upper()}}</div>
154
+ </div>
155
+ </div>
156
+ <a href="/logout" class="logout-btn">DISCONNECT</a>
157
  </div>
 
158
  <div class="container">
159
  <div class="grid">
160
  {% for t_id in allowed %}
161
  <div class="card">
162
+ <h3>>> {{t_id.upper()}}</h3>
163
  <form onsubmit="runTool(event, '{{t_id}}')">
164
+ <input type="text" id="target-{{t_id}}" placeholder="Target..." required>
165
+ <button type="submit" id="btn-{{t_id}}">START</button>
166
  </form>
 
167
  <div id="sess-{{t_id}}" class="console-box">
168
+ <div class="console-header"><span>LOG_{{t_id.upper()}}</span><a href="#" id="dl-{{t_id}}" class="dl-btn">SAVE</a></div>
169
+ <div class="console-body"><span id="out-{{t_id}}"></span><span id="cursor-{{t_id}}" class="blinking-cursor">_</span></div>
 
 
 
 
 
170
  </div>
171
  </div>
172
  {% endfor %}
173
  </div>
 
174
  </div>
 
175
  <script>
 
 
176
  function runTool(e, id) {
177
  e.preventDefault();
178
  const val = document.getElementById('target-'+id).value;
 
 
179
  const out = document.getElementById('out-'+id);
180
  const sess = document.getElementById('sess-'+id);
181
  const dl = document.getElementById('dl-'+id);
182
  const btn = document.getElementById('btn-'+id);
183
  const cursor = document.getElementById('cursor-'+id);
184
 
 
 
185
  sess.style.display = 'flex';
186
  out.innerHTML = "";
187
  dl.style.display = 'none';
188
  btn.disabled = true;
189
+ btn.innerText = "RUNNING...";
190
  cursor.style.display = "inline";
191
 
192
  const source = new EventSource(`/stream/${id}?target=${val}`);
 
 
193
  source.onmessage = function(event) {
194
  const data = JSON.parse(event.data);
195
  if(data.line) {
 
199
  if(data.done) {
200
  source.close();
201
  btn.disabled = false;
202
+ btn.innerText = "START";
203
  dl.href = "/dl/" + data.file;
204
  dl.style.display = 'inline-block';
205
  cursor.style.display = "none";
206
  }
207
  };
 
208
  source.onerror = function() {
209
  source.close();
210
  btn.disabled = false;
211
+ btn.innerText = "START";
212
+ out.innerHTML += "\\n[!] CONNECTION ERROR";
 
213
  };
214
  }
215
  </script>