<script setup>

import { useI18n } from 'vue-i18n';
const i18n = useI18n();
const t = i18n.t;

import { ref, onMounted } from 'vue';
import { Button, FormGroup, Checkbox } from '@cloudron/pankow';
import AppsModel from '../../models/AppsModel.js';

const props = defineProps([ 'app' ]);

const appsModel = AppsModel.create();

const busy = ref(false);
const robotsTxt = ref('');
const csp = ref('');
const hstsPreload = ref(false);
const submitError = ref({ robotsTxt: '', csp: '' });

function addRobotsTxtPreset(pattern) {
  if (robotsTxt.value) robotsTxt.value += '\n';
  robotsTxt.value += pattern;
}

const commonRobotsTxtMenu = [
  { label: t('app.security.robots.commonPattern.allowAll'), action: () => addRobotsTxtPreset('# Allow all\nUser-agent: *\nDisallow:') },
  { label: t('app.security.robots.commonPattern.disallowAll'), action: () => addRobotsTxtPreset('# Disable search engine indexing\n\nUser-agent: *\nDisallow: /') },
  { label: t('app.security.robots.commonPattern.disallowCommonBots'), action: () => addRobotsTxtPreset('# Disallow common bots\nUser-agent: Googlebot\nDisallow: /\n\nUser-agent: Bingbot\nDisallow: /\n\nUser-agent: Slurp\nDisallow: /\n\nUser-agent: DuckDuckBot\nDisallow: /\n\nUser-agent: Baiduspider\nDisallow: /\n\nUser-agent: YandexBot\nDisallow: /\n\nUser-agent: facebot\nDisallow: /\n\nUser-agent: ia_archiver\nDisallow: /') },
  { label: t('app.security.robots.commonPattern.disallowAdminPaths'), action: () => addRobotsTxtPreset('# Disallow admin paths\nUser-agent: *\nDisallow: /admin/\nDisallow: /internal/\nDisallow: /private/') },
  { label: t('app.security.robots.commonPattern.disallowApiPaths'), action: () => addRobotsTxtPreset('# Disallow API paths\nUser-agent: *\nDisallow: /api/\nDisallow: /v1/\nDisallow: /v2/') },
];

function addCspPreset(pattern) {
  if (csp.value) csp.value += '\n';
  csp.value += pattern;
}

const commonCspMenu = [
  { label: t('app.security.csp.commonPattern.allowEmbedding'), action: () => addCspPreset("# Allow embedding from all sites\ndefault-src 'self';\nframe-ancestors 'none';") },
  { label: t('app.security.csp.commonPattern.sameOriginEmbedding'), action: () => addCspPreset("# Allow embedding from subdomains\ndefault-src 'self';\nframe-ancestors 'self';") },
  { label: t('app.security.csp.commonPattern.allowCdnAssets'), action: () => addCspPreset("# Allow CDN assets\ndefault-src 'self';\nscript-src 'self' https://cdn.example.com;\nstyle-src 'self' https://cdn.example.com;\nimg-src 'self' data: https://cdn.example.com;\nfont-src 'self' https://cdn.example.com;\nobject-src 'none';\nframe-ancestors 'none';") },
  { label: t('app.security.csp.commonPattern.reportOnly'), action: () => addCspPreset("# Report violations. A POST request will be sent to URL below\ndefault-src 'self';\nreport-uri /csp-report;") },
  { label: t('app.security.csp.commonPattern.strictBaseline'), action: () => addCspPreset("# Secure CSP that restricts all resources to the same origin\ndefault-src 'self';\nbase-uri 'self';\nobject-src 'none';\nframe-ancestors 'none';\nform-action 'self';\nscript-src 'self';\nstyle-src 'self';\nimg-src 'self' data:;\nfont-src 'self';\nconnect-src 'self';\nmedia-src 'self';\nframe-src 'self';\nworker-src 'self';\nmanifest-src 'self';") },
];

async function onSubmit() {
  busy.value = true;
  submitError.value = {};

  const data = {
    robotsTxt: robotsTxt.value || null, // empty string resets
    csp: csp.value || null, // empty string resets
    hstsPreload: hstsPreload.value,
  };

  const [error] = await appsModel.configure(props.app.id, 'reverse_proxy', data);
  if (error) {
    if (error.body?.message.includes('CSP')) submitError.value.csp = error.body.message;
    else if (error.body?.includes('robots')) submitError.value.robotsTxt = error.body.message;
    else submitError.value.csp = JSON.stringify(error);
  }

  busy.value = false;
}

onMounted(() => {
  robotsTxt.value = props.app.reverseProxyConfig.robotsTxt || '';
  csp.value = props.app.reverseProxyConfig.csp || '';
  hstsPreload.value = props.app.reverseProxyConfig.hstsPreload || false;
});

</script>

<template>
  <div>
    <form @submit.prevent="onSubmit()" autocomplete="off">
      <fieldset :disabled="busy">
        <input style="display: none;" type="submit" />

        <FormGroup>
          <label for="robotsTxtInput" style="display: flex; justify-content: space-between;">
            <span>{{ $t('app.security.robots.title') }} <sup><a href="https://docs.cloudron.io/apps/#robotstxt" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></span>
            <Button small outline :menu="commonRobotsTxtMenu">{{ $t('app.security.robots.insertCommonRobotsTxt') }}</Button>
          </label>
          <div description>{{ $t('app.security.robots.description') }}</div>
          <textarea id="robotsTxtInput" spellcheck="false" style="white-space: pre-wrap; font-family: monospace;" v-model="robotsTxt" rows="10"></textarea>
          <div class="error-label" v-show="submitError.robotsTxt">{{ submitError.robotsTxt }}</div>
        </FormGroup>

        <FormGroup>
          <label for="cspInput" style="display: flex; justify-content: space-between;">
            <span>{{ $t('app.security.csp.title') }} <sup><a href="https://docs.cloudron.io/apps/#custom-csp" class="help" target="_blank"><i class="fa fa-question-circle"></i></a></sup></span>
            <Button small outline :menu="commonCspMenu">{{ $t('app.security.csp.insertCommonCsp') }}</Button>
          </label>
          <div description>{{ $t('app.security.csp.description') }}</div>
          <textarea id="cspInput" spellcheck="false" style="white-space: pre-wrap; font-family: monospace;" v-model="csp" rows="5"></textarea>
          <div class="error-label" v-show="submitError.csp">{{ submitError.csp }}</div>
        </FormGroup>

        <FormGroup>
          <Checkbox v-model="hstsPreload" style="display: inline-flex;" :label="$t('app.security.hstsPreload')" help-url="https://docs.cloudron.io/apps/#hsts-preload"/>
        </FormGroup>

        <br/>
        <Button @click="onSubmit()" :loading="busy" :disabled="busy">{{ $t('app.security.csp.saveAction') }}</Button>
      </fieldset>
    </form>
  </div>
</template>
