123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- <!--
- - @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- -
- - @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- -
- - @license GNU AGPL version 3 or any later version
- -
- - This program is free software: you can redistribute it and/or modify
- - it under the terms of the GNU Affero General Public License as
- - published by the Free Software Foundation, either version 3 of the
- - License, or (at your option) any later version.
- -
- - This program is distributed in the hope that it will be useful,
- - but WITHOUT ANY WARRANTY; without even the implied warranty of
- - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- - GNU Affero General Public License for more details.
- -
- - You should have received a copy of the GNU Affero General Public License
- - along with this program. If not, see <http://www.gnu.org/licenses/>.
- -->
-
- <template>
- <form ref="loginForm"
- method="post"
- name="login"
- :action="OC.generateUrl('login')"
- @submit="submit">
- <fieldset>
- <div v-if="apacheAuthFailed"
- class="warning">
- {{ t('core', 'Server side authentication failed!') }}<br>
- <small>{{ t('core', 'Please contact your administrator.') }}
- </small>
- </div>
- <div v-for="(message, index) in messages"
- :key="index"
- class="warning">
- {{ message }}<br>
- </div>
- <div v-if="internalException"
- class="warning">
- {{ t('core', 'An internal error occurred.') }}<br>
- <small>{{ t('core', 'Please try again or contact your administrator.') }}
- </small>
- </div>
- <div id="message"
- class="hidden">
- <img class="float-spinner"
- alt=""
- :src="OC.imagePath('core', 'loading-dark.gif')">
- <span id="messageText" />
- <!-- the following div ensures that the spinner is always inside the #message div -->
- <div style="clear: both;" />
- </div>
- <p class="grouptop"
- :class="{shake: invalidPassword}">
- <input id="user"
- ref="user"
- v-model="user"
- type="text"
- name="user"
- :autocomplete="autoCompleteAllowed ? 'on' : 'off'"
- :placeholder="t('core', 'Username or email')"
- :aria-label="t('core', 'Username or email')"
- required
- @change="updateUsername">
- <label for="user" class="infield">{{ t('core', 'Username or email') }}</label>
- </p>
-
- <p class="groupbottom"
- :class="{shake: invalidPassword}">
- <input id="password"
- ref="password"
- :type="passwordInputType"
- class="password-with-toggle"
- name="password"
- :autocomplete="autoCompleteAllowed ? 'on' : 'off'"
- :placeholder="t('core', 'Password')"
- :aria-label="t('core', 'Password')"
- required>
- <label for="password"
- class="infield">{{ t('Password') }}</label>
- <a href="#" class="toggle-password" @click.stop.prevent="togglePassword">
- <img :src="OC.imagePath('core', 'actions/toggle.svg')">
- </a>
- </p>
-
- <LoginButton :loading="loading" :inverted-colors="invertedColors" />
-
- <p v-if="invalidPassword"
- class="warning wrongPasswordMsg">
- {{ t('core', 'Wrong username or password.') }}
- </p>
- <p v-else-if="userDisabled"
- class="warning userDisabledMsg">
- {{ t('lib', 'User disabled') }}
- </p>
-
- <p v-if="throttleDelay && throttleDelay > 5000"
- class="warning throttledMsg">
- {{ t('core', 'We have detected multiple invalid login attempts from your IP. Therefore your next login is throttled up to 30 seconds.') }}
- </p>
-
- <input v-if="redirectUrl"
- type="hidden"
- name="redirect_url"
- :value="redirectUrl">
- <input type="hidden"
- name="timezone"
- :value="timezone">
- <input type="hidden"
- name="timezone_offset"
- :value="timezoneOffset">
- <input type="hidden"
- name="requesttoken"
- :value="OC.requestToken">
- <input v-if="directLogin"
- type="hidden"
- name="direct"
- value="1">
- </fieldset>
- </form>
- </template>
-
- <script>
- import jstz from 'jstimezonedetect'
- import LoginButton from './LoginButton'
-
- export default {
- name: 'LoginForm',
- components: { LoginButton },
- props: {
- username: {
- type: String,
- default: '',
- },
- redirectUrl: {
- type: String,
- },
- errors: {
- type: Array,
- default: () => [],
- },
- messages: {
- type: Array,
- default: () => [],
- },
- throttleDelay: {
- type: Number,
- },
- invertedColors: {
- type: Boolean,
- default: false,
- },
- autoCompleteAllowed: {
- type: Boolean,
- default: true,
- },
- directLogin: {
- type: Boolean,
- default: false,
- },
- },
- data() {
- return {
- loading: false,
- timezone: jstz.determine().name(),
- timezoneOffset: (-new Date().getTimezoneOffset() / 60),
- user: this.username,
- password: '',
- passwordInputType: 'password',
- }
- },
- computed: {
- apacheAuthFailed() {
- return this.errors.indexOf('apacheAuthFailed') !== -1
- },
- internalException() {
- return this.errors.indexOf('internalexception') !== -1
- },
- invalidPassword() {
- return this.errors.indexOf('invalidpassword') !== -1
- },
- userDisabled() {
- return this.errors.indexOf('userdisabled') !== -1
- },
- },
- mounted() {
- if (this.username === '') {
- this.$refs.user.focus()
- } else {
- this.$refs.password.focus()
- }
- },
- methods: {
- togglePassword() {
- if (this.passwordInputType === 'password') {
- this.passwordInputType = 'text'
- } else {
- this.passwordInputType = 'password'
- }
- },
- updateUsername() {
- this.$emit('update:username', this.user)
- },
- submit() {
- this.loading = true
- this.$emit('submit')
- },
- },
- }
- </script>
-
- <style scoped>
-
- </style>
|