"""
MontanaSign — Сервис подписи iOS приложений
efir.org/install
Модель как LazyShop:
1. Пользователь регистрирует UDID
2. Мы выдаём сертификат (или подписываем своим)
3. .ipa скачивается и устанавливается
4. Apple не контролирует
"""
from flask import Flask, request, jsonify, send_file, render_template_string
from flask_cors import CORS
import os
import subprocess
import hashlib
import json
import sqlite3
from datetime import datetime, timedelta
import secrets
app = Flask(__name__)
CORS(app)
# Конфигурация
UPLOAD_FOLDER = '/var/montana/ipa'
SIGNED_FOLDER = '/var/montana/signed'
CERTS_FOLDER = '/var/montana/certs'
DATABASE = '/var/montana/montanasign.db'
# IPA файлы Montana (беззнаковые)
MONTANA_APPS = {
'wallet': {
'name': 'Montana Wallet',
'bundle_id': 'network.montana.wallet',
'version': '1.0.0',
'ipa': 'MontanaWallet.ipa',
'icon': 'wallet_icon.png',
'description': 'Кошелёк Ɉ — баланс и переводы'
},
'junona': {
'name': 'Junona AI',
'bundle_id': 'network.montana.junona',
'version': '1.0.0',
'ipa': 'JunonaAI.ipa',
'icon': 'junona_icon.png',
'description': 'Чат с ИИ Montana Protocol'
},
'contracts': {
'name': 'Montana Contracts',
'bundle_id': 'network.montana.contracts',
'version': '1.0.0',
'ipa': 'MontanaContracts.ipa',
'icon': 'contracts_icon.png',
'description': 'Контракты Bitcoin Pizza Style'
}
}
def init_db():
"""Инициализация базы данных"""
conn = sqlite3.connect(DATABASE)
c = conn.cursor()
c.execute('''
CREATE TABLE IF NOT EXISTS devices (
udid TEXT PRIMARY KEY,
user_id TEXT,
device_name TEXT,
model TEXT,
registered_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP,
certificate_id TEXT
)
''')
c.execute('''
CREATE TABLE IF NOT EXISTS certificates (
cert_id TEXT PRIMARY KEY,
udid TEXT,
cert_data BLOB,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP,
revoked BOOLEAN DEFAULT FALSE
)
''')
c.execute('''
CREATE TABLE IF NOT EXISTS installations (
id INTEGER PRIMARY KEY AUTOINCREMENT,
udid TEXT,
app_id TEXT,
installed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
version TEXT
)
''')
conn.commit()
conn.close()
# ═══════════════════════════════════════════════════════════════
# LANDING PAGE
# ═══════════════════════════════════════════════════════════════
LANDING_HTML = '''
Montana Install — Установка без App Store
💰
Montana Wallet
Кошелёк Ɉ — баланс и переводы
🤖
Junona AI
Чат с ИИ Montana Protocol
📄
Montana Contracts
Контракты Bitcoin Pizza Style
2
После установки
Настройки → Основные → VPN и управление устройством → Доверять сертификату Montana
'''
@app.route('/')
def landing():
return render_template_string(LANDING_HTML)
# ═══════════════════════════════════════════════════════════════
# API
# ═══════════════════════════════════════════════════════════════
@app.route('/api/register', methods=['POST'])
def register_device():
"""Регистрация устройства по UDID"""
data = request.json
udid = data.get('udid', '').strip()
if not udid or len(udid) < 20:
return jsonify({'success': False, 'error': 'Invalid UDID'})
conn = sqlite3.connect(DATABASE)
c = conn.cursor()
# Проверяем существует ли
c.execute('SELECT * FROM devices WHERE udid = ?', (udid,))
existing = c.fetchone()
if existing:
conn.close()
return jsonify({'success': True, 'message': 'Already registered'})
# Регистрируем
expires_at = datetime.now() + timedelta(days=365)
cert_id = secrets.token_hex(16)
c.execute('''
INSERT INTO devices (udid, expires_at, certificate_id)
VALUES (?, ?, ?)
''', (udid, expires_at, cert_id))
conn.commit()
conn.close()
return jsonify({
'success': True,
'message': 'Device registered',
'expires': expires_at.isoformat()
})
@app.route('/api/manifest/')
def get_manifest(app_id):
"""Генерация manifest.plist для установки"""
udid = request.args.get('udid')
if app_id not in MONTANA_APPS:
return 'App not found', 404
app = MONTANA_APPS[app_id]
# Генерируем manifest
manifest = f'''
items
assets
kind
software-package
url
{request.host_url}api/download/{app_id}?udid={udid}
kind
display-image
url
{request.host_url}static/icons/{app['icon']}
metadata
bundle-identifier
{app['bundle_id']}
bundle-version
{app['version']}
kind
software
title
{app['name']}
'''
return manifest, 200, {'Content-Type': 'application/xml'}
@app.route('/api/download/')
def download_ipa(app_id):
"""Скачивание подписанного IPA"""
udid = request.args.get('udid')
if app_id not in MONTANA_APPS:
return 'App not found', 404
app = MONTANA_APPS[app_id]
# Путь к подписанному IPA для этого UDID
signed_path = os.path.join(SIGNED_FOLDER, udid, app['ipa'])
# Если ещё не подписан — подписываем
if not os.path.exists(signed_path):
sign_ipa_for_udid(app_id, udid)
if os.path.exists(signed_path):
# Логируем установку
conn = sqlite3.connect(DATABASE)
c = conn.cursor()
c.execute('''
INSERT INTO installations (udid, app_id, version)
VALUES (?, ?, ?)
''', (udid, app_id, app['version']))
conn.commit()
conn.close()
return send_file(signed_path, as_attachment=True, download_name=app['ipa'])
return 'Signing failed', 500
def sign_ipa_for_udid(app_id: str, udid: str):
"""Подписать IPA для конкретного UDID"""
app = MONTANA_APPS[app_id]
unsigned_path = os.path.join(UPLOAD_FOLDER, app['ipa'])
output_dir = os.path.join(SIGNED_FOLDER, udid)
os.makedirs(output_dir, exist_ok=True)
output_path = os.path.join(output_dir, app['ipa'])
# Используем zsign или ldid для подписи
# zsign -k cert.p12 -m profile.mobileprovision -o output.ipa input.ipa
cert_path = os.path.join(CERTS_FOLDER, 'montana.p12')
profile_path = os.path.join(CERTS_FOLDER, f'{udid}.mobileprovision')
try:
subprocess.run([
'zsign',
'-k', cert_path,
'-m', profile_path,
'-o', output_path,
unsigned_path
], check=True)
return True
except subprocess.CalledProcessError as e:
print(f"Signing failed: {e}")
return False
@app.route('/api/apps')
def list_apps():
"""Список приложений"""
return jsonify(MONTANA_APPS)
@app.route('/api/stats')
def stats():
"""Статистика"""
conn = sqlite3.connect(DATABASE)
c = conn.cursor()
c.execute('SELECT COUNT(*) FROM devices')
devices = c.fetchone()[0]
c.execute('SELECT COUNT(*) FROM installations')
installs = c.fetchone()[0]
conn.close()
return jsonify({
'registered_devices': devices,
'total_installations': installs
})
# ═══════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════
if __name__ == '__main__':
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(SIGNED_FOLDER, exist_ok=True)
os.makedirs(CERTS_FOLDER, exist_ok=True)
init_db()
print("🏔 MontanaSign — iOS Distribution Service")
print(" efir.org/install")
print("")
print(" Модель: LazyShop-style")
print(" 1. Пользователь регистрирует UDID")
print(" 2. Мы подписываем IPA")
print(" 3. Apple не контролирует")
print("")
app.run(host='0.0.0.0', port=8080, debug=True)