Mini Shell

Direktori : /home/ukubnwwt/
Upload File :
Current File : /home/ukubnwwt/uviewerdownload

<!-- uviewerdownload.html -->
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Download UViewer</title>
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Inter:400,500,600,700&display=swap">
  <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.10.0/axios.min.js" integrity="sha512-WkZrEcQ5LMyNy6Y2PQf+Tu3vMcsmKKRKuPXtJSTHQJ3mpuvLRlA5dlDDhrrcXfyWr6Z/y3wIMfjfqVFO/gDZYQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <style>
    body {
      font-family: 'Inter', sans-serif;
      margin: 0;
      padding: 0;
      background: #f8fafc;
    }
    .container {
      display: flex;
      align-items: center;
      justify-content: center;
      flex-direction: column;
      min-height: 100vh;
      padding: 1rem;
    }
    .download-message {
      background: #e0f2fe;
      color: #0369a1;
      padding: 1rem 1.5rem;
      border-radius: 0.5rem;
      margin-bottom: 2rem;
      font-size: 1.125rem;
    }
    .hidden-link {
      display: none;
    }
  </style>
</head>
<body>
  <div class="container">
    <div class="download-message">
      Please create an account or log in to download UViewer
    </div>

    <div id="app"></div>

    <!-- Hidden download link -->
    <a id="uviewerDownloadLink" class="hidden-link" href="https://ukubona.cloud/viewers/UViewer_Installer.exe" download></a>
  </div>

  <script type="module">
    import { createApp, ref, reactive, computed } from 'https://unpkg.com/vue@3/dist/vue.esm-browser.js';

    const app = {
      setup() {
        const isLogin = ref(true);
        const message = ref('');
        const loading = ref(false);
        const form = reactive({ email: '', password: '', name: '' });
        const confirmPassword = ref('');
        const showPassword = ref(false);
        const error = ref('');

        const baseURL = 'https://backend.ukubona.cloud/';
        const deviceID = crypto.randomUUID();

        const passwordMismatch = computed(() => isLogin.value ? false : form.password !== confirmPassword.value);

        const clearForm = () => {
          form.email = '';
          form.password = '';
          form.name = '';
          confirmPassword.value = '';
          error.value = '';
        };

        const saveAccessToken = (token) => {
          sessionStorage.setItem('access_token', token);
          setTimeout(() => sessionStorage.removeItem('access_token'), 15 * 60 * 1000); // Clear in 15 mins
        };

        const triggerDownload = () => {
          const link = document.getElementById('uviewerDownloadLink');
          if (link) link.click();
        };

        const validateAndDownload = async () => {
          const token = sessionStorage.getItem('access_token');
          if (!token) return;

          try {
            const res = await axios.get(baseURL + 'accounts/userdata', {
              headers: {
                Authorization: `Bearer ${token}`,
                'Device-ID': deviceID
              }
            });
            if (res.status === 200) {
              triggerDownload();
            }
          } catch (err) {
            error.value = 'Access expired or invalid.';
            sessionStorage.removeItem('access_token');
          }
        };

        const handleSubmit = async () => {
          error.value = '';
          if (!form.email || !form.password || (!isLogin.value && !form.name)) {
            error.value = 'All fields are required';
            return;
          }

          if (!isLogin.value && passwordMismatch.value) {
            error.value = 'Passwords do not match';
            return;
          }

          loading.value = true;

          try {
            if (isLogin.value) {
              const res = await axios.post(baseURL + 'accounts/token/', {
                email: form.email,
                password: form.password
              }, {
                headers: { 'Device-ID': deviceID }
              });
              saveAccessToken(res.data.access);
              await validateAndDownload();
            } else {
              await axios.post(baseURL + 'accounts/user-create/', {
                email: form.email,
                password: form.password,
                name: form.name
              }, {
                headers: { 'Device-ID': deviceID }
              });
              isLogin.value = true;
              clearForm();
              message.value = 'Signup successful. Please log in to continue.';
            }
          } catch (err) {
            error.value = err?.response?.data?.detail || 'Something went wrong.';
          } finally {
            loading.value = false;
          }
        };

        return {
          isLogin,
          message,
          loading,
          form,
          confirmPassword,
          showPassword,
          passwordMismatch,
          error,
          handleSubmit
        };
      },
      template: `
        <div class="card">
          <h2>{{ isLogin ? 'Login' : 'Sign Up' }}</h2>
          <p v-if="message" style="color: green">{{ message }}</p>
          <form @submit.prevent="handleSubmit">
            <div v-if="!isLogin">
              <input v-model="form.name" placeholder="Full Name" required />
            </div>
            <input v-model="form.email" placeholder="Email" type="email" required />
            <input :type="showPassword ? 'text' : 'password'" v-model="form.password" placeholder="Password" required />
            <div v-if="!isLogin">
              <input :type="showPassword ? 'text' : 'password'" v-model="confirmPassword" placeholder="Confirm Password" required />
              <p v-if="passwordMismatch" style="color:red">Passwords do not match</p>
            </div>
            <label>
              <input type="checkbox" v-model="showPassword" /> Show Password
            </label>
            <button type="submit" :disabled="loading">{{ loading ? 'Processing...' : (isLogin ? 'Login' : 'Sign Up') }}</button>
            <p v-if="error" style="color:red">{{ error }}</p>
          </form>
          <button @click="isLogin = !isLogin" style="margin-top: 1rem">
            {{ isLogin ? 'Create an account' : 'Already have an account? Login' }}
          </button>
        </div>
      `
    };

    createApp(app).mount('#app');
  </script>
</body>
</html>