sudo-soldier commited on
Commit
102fb60
·
verified ·
1 Parent(s): 9ebdcbe

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +111 -22
app.py CHANGED
@@ -1,36 +1,125 @@
1
  import os
2
  import subprocess
3
- from flask import Flask, request, send_file
 
 
 
 
4
 
5
  app = Flask(__name__)
6
 
7
- # Endpoint to generate APK from PWA URL
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  @app.route("/generate-apk", methods=["POST"])
9
  def generate_apk():
10
- pwa_url = request.form["url"]
 
 
 
 
11
 
12
- if not pwa_url:
13
- return "URL is required", 400
14
 
15
- # Create the Bubblewrap configuration and generate APK
 
 
 
16
  try:
17
- subprocess.run(["bubblewrap", "init", "--manifest", pwa_url], check=True)
18
-
19
- # Build the APK
20
- subprocess.run(["bubblewrap", "build"], check=True)
21
-
22
- # Assuming APK is stored in 'output' directory
23
- apk_path = "output/app-release.apk"
24
 
25
- # Check if APK was generated
26
- if os.path.exists(apk_path):
27
- return send_file(apk_path, as_attachment=True)
28
- else:
29
- return "APK generation failed", 500
30
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  except subprocess.CalledProcessError as e:
32
- return f"Error generating APK: {str(e)}", 500
 
 
 
 
 
 
 
 
33
 
34
- if __name__ == "__main__":
35
- app.run(host="0.0.0.0", port=7860)
 
 
 
 
 
 
 
36
 
 
 
 
 
 
 
 
 
1
  import os
2
  import subprocess
3
+ import tempfile
4
+ import shutil
5
+ import re
6
+ from flask import Flask, request, send_file, jsonify
7
+ from werkzeug.utils import secure_filename
8
 
9
  app = Flask(__name__)
10
 
11
+ # Configuration
12
+ app.config['MAX_CONTENT_LENGTH'] = 1 * 1024 * 1024 # 1MB max upload size
13
+ app.config['ALLOWED_HOSTS'] = ['yourdomain.com'] # Add your production domain
14
+ app.config['BUBBLEWRAP_MIN_VERSION'] = '1.0.0' # Minimum required version
15
+
16
+ # Validate URL format
17
+ def is_valid_url(url):
18
+ regex = re.compile(
19
+ r'^(https?://)?' # http:// or https://
20
+ r'([a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}' # domain
21
+ r'(/[a-zA-Z0-9-._~:/?#[\]@!$&\'()*+,;=]*)?$', # path
22
+ re.IGNORECASE
23
+ )
24
+ return re.match(regex, url) is not None
25
+
26
+ # Check if bubblewrap is available
27
+ def check_bubblewrap():
28
+ try:
29
+ result = subprocess.run(['bubblewrap', '--version'],
30
+ capture_output=True, text=True, check=True)
31
+ version = result.stdout.strip()
32
+ if version < app.config['BUBBLEWRAP_MIN_VERSION']:
33
+ raise Exception(f"Bubblewrap version {version} is below minimum required version")
34
+ return True
35
+ except Exception as e:
36
+ app.logger.error(f"Bubblewrap check failed: {str(e)}")
37
+ return False
38
+
39
+ # Clean up directory
40
+ def cleanup_directory(dir_path):
41
+ try:
42
+ if os.path.exists(dir_path):
43
+ shutil.rmtree(dir_path)
44
+ except Exception as e:
45
+ app.logger.error(f"Cleanup failed for {dir_path}: {str(e)}")
46
+
47
  @app.route("/generate-apk", methods=["POST"])
48
  def generate_apk():
49
+ # Validate request
50
+ if 'url' not in request.form:
51
+ return jsonify({"error": "URL parameter is required"}), 400
52
+
53
+ pwa_url = request.form['url'].strip()
54
 
55
+ if not is_valid_url(pwa_url):
56
+ return jsonify({"error": "Invalid URL format"}), 400
57
 
58
+ # Create temp directory
59
+ temp_dir = tempfile.mkdtemp(prefix='pwa2apk_')
60
+ os.chdir(temp_dir) # Work in temp directory
61
+
62
  try:
63
+ # Initialize project
64
+ init_cmd = [
65
+ 'bubblewrap', 'init',
66
+ '--manifest', pwa_url,
67
+ '--directory', temp_dir,
68
+ '--non-interactive'
69
+ ]
70
 
71
+ subprocess.run(init_cmd, check=True, timeout=300,
72
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
73
+
74
+ # Build APK
75
+ build_cmd = ['bubblewrap', 'build']
76
+ subprocess.run(build_cmd, check=True, timeout=600,
77
+ stdout=subprocess.PIPE, stderr=subprocess.PIPE)
78
+
79
+ # Verify APK was created
80
+ apk_path = os.path.join(temp_dir, 'app-release.apk')
81
+ if not os.path.exists(apk_path):
82
+ raise Exception("APK file not found after build")
83
+
84
+ # Secure filename for download
85
+ domain = pwa_url.split('//')[-1].split('/')[0].replace('.', '_')
86
+ apk_name = secure_filename(f"{domain}_app.apk")
87
+
88
+ # Return the file
89
+ return send_file(
90
+ apk_path,
91
+ as_attachment=True,
92
+ download_name=apk_name,
93
+ mimetype='application/vnd.android.package-archive'
94
+ )
95
+
96
+ except subprocess.TimeoutExpired:
97
+ return jsonify({"error": "APK generation timed out"}), 504
98
  except subprocess.CalledProcessError as e:
99
+ app.logger.error(f"Build failed: {e.stderr}")
100
+ return jsonify({"error": "APK generation failed", "details": str(e)}), 500
101
+ except Exception as e:
102
+ app.logger.error(f"Unexpected error: {str(e)}")
103
+ return jsonify({"error": "APK generation failed", "details": str(e)}), 500
104
+ finally:
105
+ # Clean up
106
+ os.chdir('/') # Change out of directory before cleanup
107
+ cleanup_directory(temp_dir)
108
 
109
+ @app.before_request
110
+ def before_request():
111
+ # Simple host validation
112
+ if request.headers.get('Host') not in app.config['ALLOWED_HOSTS']:
113
+ return jsonify({"error": "Unauthorized host"}), 403
114
+
115
+ # Check bubblewrap is available
116
+ if not check_bubblewrap():
117
+ return jsonify({"error": "Service temporarily unavailable"}), 503
118
 
119
+ if __name__ == "__main__":
120
+ # Verify dependencies at startup
121
+ if not check_bubblewrap():
122
+ print("Error: Bubblewrap not available or version too old")
123
+ exit(1)
124
+
125
+ app.run(host="0.0.0.0", port=7860, threaded=True)