Heroku/web-resources/initial_root.jinja2

624 lines
18 KiB
Django/Jinja
Executable File

<!--
█ █ ▀ █▄▀ ▄▀█ █▀█ ▀ ▄▀█ ▀█▀ ▄▀█ █▀▄▀█ ▄▀█
█▀█ █ █ █ █▀█ █▀▄ █ ▄ █▀█ █ █▀█ █ ▀ █ █▀█
Copyright 2022 t.me/hikariatama
Licensed under the GNU GPLv3
-->
{% extends "base.jinja2" %}
{% block head %}
<script src="https://cdn.jsdelivr.net/npm/scrypt-async@2.0.1/scrypt-async.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<style>
@import url('https://fonts.googleapis.com/css2?family=Josefin+Sans&family=Open+Sans:wght@300&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Hubballi&display=swap');
.button {
border-radius: 5px;
padding: 10px 20px;
border: none;
color: #eee;
margin: 5px 0;
background: transparent;
border: 2px solid #aaa;
cursor: pointer;
transition: box-shadow .2s ease;
user-select: none;
}
.button:hover {
box-shadow: inset 5px 5px 3px rgba(255, 255, 255, .1),
inset -5px -5px 3px rgba(255, 255, 255, .1);
}
.signin_block {
display: inline-block;
}
.signin_block ul {
margin: 0;
list-style: none;
padding: 0;
}
.signin_block li {
width: 100%;
}
.signin_block h1 {
margin: 0;
color: #eee;
font-size: 22px;
padding: 10px;
font-family: "Open Sans";
}
.hamburger, .menu {
display: none;
}
</style>
<style type="text/css">
body, html {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
}
body {
/*background: linear-gradient(-45deg, #007700 0%, #004400 100%);*/
transition: all 2s ease;
background: #16181d;
}
#sky {
width: 100vw;
height: 100vh;
position: fixed;
overflow: hidden;
margin: 0;
padding: 0;
}
#shootingstars {
margin: 0;
padding: 0;
width: 150vh;
height: 100vw;
position: fixed;
overflow: hidden;
transform: translatex(calc(50vw - 50%)) translatey(calc(50vh - 50%))
rotate(120deg);
}
.wish {
height: 2px;
top: 300px;
width: 100px;
margin: 0;
opacity: 0;
padding: 0;
background-color: white;
position: absolute;
background: linear-gradient(-45deg, white, rgba(0, 0, 255, 0));
filter: drop-shadow(0 0 6px white);
overflow: hidden;
}
.title {
font-size: 50px;
font-family: Hubballi;
text-align: center;
color: #fff;
width: 100%;
z-index: 2;
position: relative;
height: 50px;
line-height: 50px;
}
.description {
font-size: 24px;
color: #eee;
text-align: center;
width: 100%;
z-index: 2;
position: relative;
padding-top: 20px;
line-height: 1.3;
font-family: Hubballi;
}
.wrapper {
width: 100%;
height: 100%;
position: absolute;
justify-content: center;
align-items: center;
display: flex;
flex-direction: column;
}
#root {
position: absolute;
top: 0;
right: 0;
left: 0;
bottom: 0;
margin: auto;
}
.darken {
position: absolute;
width: 100%;
height: 100%;
z-index: 1;
background: rgba(0, 0, 0, .1);
top: 0;
bottom: 0;
right: 0;
left: 0;
margin: auto;
}
.main_content {
display: none;
}
.center {
justify-content: center;
align-items: center;
display: flex;
position: relative;
z-index: 2;
margin-top: 20px;
}
.blur {
padding: 4rem 8rem;
border-radius: 0.375rem;
background-color: rgba(22, 24, 29, .5);
border: 1px solid rgba(42, 46, 55, 1);
backdrop-filter: blur(6px);
position: relative;
z-index: 99;
}
.bg {
background: url(https://github.com/hikariatama/assets/raw/master/bg.png);
background-repeat: no-repeat;
background-size: contain;
width: 80vw;
height: 60vh;
position: absolute;
z-index: 1;
background-position: center;
display: none;
filter: hue-rotate(155deg);
transition: .3s;
animation: floating 5s infinite ease-in-out;
}
@keyframes floating {
from {
transform: translateY(-10px);
}
50% {
transform: translateY(10px);
}
to {
transform: translateY(-10px);
}
}
@media screen and (max-width: 736px) {
.blur {
width: 100%;
height: 100%;
padding: 1.5rem;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.bg {
width: 100vh;
height: 100vw;
transform: rotate(90deg);
}
}
input {
background: transparent;
border: 1px solid #eee;
outline: none;
padding: 10px 15px;
border-radius: 10px;
color: #fff;
text-align: center;
}
label {
margin: 0 10px;
color: #eee;
user-select: none;
}
#continue_btn {
padding: 10px 15px;
background: #0d47a1;
border-radius: 10px;
user-select: none;
color: #fff;
cursor: pointer;
text-align: center;
border: 1px solid #1a237e;
margin: 10px 0;
transition: all .3s ease;
margin-left: 5px;
}
#continue_btn:hover {
background-color: #1a237e;
}
#continue_btn:active {
background-color: #311b92;
}
#continue_btn.error {
background-color: #c62828;
transition: all .3s ease;
}
#continue_btn, #block_api_id, #block_api_hash, #block_phone, #block_2fa {
display: none;
}
.red_state {
filter: hue-rotate(0deg);
}
.blue_state {
filter: hue-rotate(203deg);
}
</style>
{% endblock %}
{% block content %}
{% endblock %}
{% block after %}
<div class="wrapper">
<div class="bg invert">
</div>
<div class="blur">
<div class="title">Hikka</div>
<div class="description">Ultimate userbot.<br>Best <span style="color:#28a0dc">Telegram</span> userbot.<br><b>Ever</b>.</div>
<div class="center">
<div class="button" id="get_started">Get started</div>
<span id="block_api_id">
<label class="api_id" for="api_id">API ID: </label>
<input class="api_id" id="api_id" placeholder="2020" style="width: 4em;">
</span>
<span id="block_api_hash">
<label class="api_hash" for="api_hash">API HASH: </label>
<input class="api_hash" id="api_hash" placeholder="w7i07l02i6hymgg03ncq6esmr3t4c9kl" style="width: 24em;">
</span>
<span id="block_phone">
<label class="phone" for="phone">Phone: </label>
<input class="phone" id="phone" placeholder="+79999999999" style="width: 12em;">
</span>
<span id="block_2fa">
<label class="_2fa" for="_2fa">2FA Password: </label>
<input class="_2fa" id="_2fa" placeholder="passw0rd" style="width: 12em;" type="password">
</span>
<div id="continue_btn">Continue</div>
</div>
</div>
<div id="root">
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script src="//cdn.jsdelivr.net/npm/sweetalert2@11"></script>
<script type="text/javascript">
$(document).ready(function() {
$('.bg').hide().delay(2000).fadeIn(500);
});
$("#get_started").click(() => {
$("#get_started").fadeOut(500, () => {
cnt_btn.setAttribute('current-step', 'api_id');
$("#block_api_id").hide().fadeIn(500);
$("#continue_btn").hide().fadeIn(500);
});
});
function isInt(value) {
var x = parseFloat(value);
return !isNaN(value) && (x | 0) === x;
}
function isValidPhone(p) {
var phoneRe = /^[+]?\d{11,13}$/;
return phoneRe.test(p);
}
var _api_id = "", _api_hash = "", _phone = "", _2fa_pass = "", _tg_pass = "";
const cnt_btn = document.querySelector('#continue_btn');
cnt_btn.onclick = (e) => {
if(cnt_btn.disabled) return;
let step = cnt_btn.getAttribute('current-step');
if(step == "api_id") {
let api_id = document.querySelector('#api_id').value;
if(api_id.length < 4 || !isInt(api_id)) {
$(".bg").addClass("red_state");
cnt_btn.disabled = true;
setTimeout(() => {
cnt_btn.disabled = false;
$(".bg").removeClass("red_state");
}, 1000);
return;
}
_api_id = parseInt(api_id);
cnt_btn.setAttribute('current-step', 'api_hash');
$("#block_api_id").fadeOut(() => {
$("#block_api_hash").hide().fadeIn();
});
} else if (step == "api_hash") {
let api_hash = document.querySelector('#api_hash').value;
if(api_hash.length != 32) {
$(".bg").addClass("red_state");
cnt_btn.disabled = true;
setTimeout(() => {
cnt_btn.disabled = false;
$(".bg").removeClass("red_state");
}, 1000);
return;
}
_api_hash = api_hash;
fetch("/setApi", {
method: "PUT",
body: _api_hash + _api_id,
credentials: "include"
})
.then(function (response) {
if (!response.ok) {
Swal.fire({
'icon': 'error',
'title': 'Error occured while saving credentials'
});
} else {
cnt_btn.setAttribute('current-step', 'phone');
$("#block_api_hash").fadeOut(() => {
$("#block_phone").hide().fadeIn();
});
}
})
.catch(function (response) {
Swal.fire({
'icon': 'error',
'title': 'Error occured while saving credentials'
});
});
} else if (step == "phone" || step == "2fa") {
if(step == "phone") {
let phone = document.querySelector('#phone').value;
if(!isValidPhone(phone)) {
$(".bg").addClass("red_state");
cnt_btn.disabled = true;
setTimeout(() => {
cnt_btn.disabled = false;
$(".bg").removeClass("red_state");
}, 1000);
return;
}
_phone = phone;
fetch("/sendTgCode", {method: "POST", body: _phone, credentials: "include"})
.then(function (response) {
if (!response.ok) {
Swal.fire({
'icon': 'error',
'title': 'Code send failed'
});
} else {
Swal.fire({
title: 'Enter received code',
input: 'text',
inputAttributes: {
autocapitalize: 'off'
},
showCancelButton: false,
confirmButtonText: 'Confirm',
showLoaderOnConfirm: true,
preConfirm: (login) => {
_tg_pass = login
return fetch("/tgCode", {method: "POST", body: _tg_pass + "\n" + _phone + "\n" + _2fa_pass})
.then(function(response) {
if (!response.ok) {
console.log(response);
if (response.status == 403) {
Swal.showValidationMessage('Code is incorrect!');
} else if (response.status == 401) {
cnt_btn.setAttribute('current-step', '2fa');
$("#block_phone").fadeOut(() => {
$("#block_2fa").hide().fadeIn();
});
} else if (response.status == 404) {
// Code expired, must re-send code request. Close dialog and wait for user action.
Swal.showValidationMessage('Code is expired!');
} else {
Swal.showValidationMessage('Internal server error');
}
} else {
Swal.fire({
title: 'Enter Heroku token',
text: 'Leave empty to NOT install to Heroku',
input: 'text',
inputAttributes: {
autocapitalize: 'off'
},
showCancelButton: false,
confirmButtonText: 'Confirm',
showLoaderOnConfirm: true,
preConfirm: (heroku_token) => {
return fetch("/finishLogin", {method: "POST", body: heroku_token, credentials: "include"})
.then(function (response) {
if (!response.ok) {
Swal.fire({
'icon': 'error',
'text': 'Login confirmation error'
})
} else {
Swal.fire({
'icon': 'success',
'text': 'Auth successful!',
'timer': 1000
});
setTimeout(() => {
window.location.reload();
}, 1500);
}
})
.catch(function (response) {
Swal.fire({
'icon': 'error',
'text': 'Login confirmation error'
})
});
},
allowOutsideClick: () => !Swal.isLoading()
})
}
})
.catch(error => {
Swal.showValidationMessage(
'Auth failed: ' + error.toString()
)
})
},
allowOutsideClick: () => !Swal.isLoading()
})
}
})
.catch(function (error) {
Swal.fire({
'icon': 'error',
'title': 'Code send failed'
});
});
} else {
let _2fa = document.querySelector('#_2fa').value;
_2fa_pass = _2fa;
fetch("/tgCode", {method: "POST", body: _tg_pass + "\n" + _phone + "\n" + _2fa_pass})
.then(function(response) {
if (!response.ok) {
console.log(response);
if (response.status == 403) {
Swal.showValidationMessage('Code is incorrect!');
} else if (response.status == 401) {
cnt_btn.setAttribute('current-step', '2fa');
$("#block_phone").fadeOut(() => {
$("#block_2fa").hide().fadeIn();
});
} else if (response.status == 404) {
// Code expired, must re-send code request. Close dialog and wait for user action.
Swal.showValidationMessage('Code is expired!');
} else {
Swal.showValidationMessage('Internal server error');
}
} else {
{% if hosting %}
fetch("/finishLogin", {method: "POST", body: '', credentials: "include"})
.then(function (response) {
if (!response.ok) {
Swal.fire({
'icon': 'error',
'text': 'Login confirmation error'
})
} else {
Swal.fire({
'icon': 'success',
'text': 'Auth successful!',
'timer': 1000
});
setTimeout(() => {
window.location.reload();
}, 1500);
}
})
.catch(function (response) {
Swal.fire({
'icon': 'error',
'text': 'Login confirmation error'
})
});
{% else %}
Swal.fire({
title: 'Enter Heroku token',
text: 'Leave empty to NOT install to Heroku',
input: 'text',
inputAttributes: {
autocapitalize: 'off'
},
showCancelButton: false,
confirmButtonText: 'Confirm',
showLoaderOnConfirm: true,
preConfirm: (heroku_token) => {
return fetch("/finishLogin", {method: "POST", body: heroku_token, credentials: "include"})
.then(function (response) {
if (!response.ok) {
Swal.fire({
'icon': 'error',
'text': 'Login confirmation error'
})
} else {
Swal.fire({
'icon': 'success',
'text': 'Auth successful!',
'timer': 1000
});
setTimeout(() => {
window.location.reload();
}, 1500);
}
})
.catch(function (response) {
Swal.fire({
'icon': 'error',
'text': 'Login confirmation error'
})
});
},
allowOutsideClick: () => !Swal.isLoading()
})
{% endif %}
}
})
.catch(error => {
Swal.showValidationMessage(
'Auth failed: ' + error.toString()
)
})
}
}
}
</script>
{% endblock %}