Adding initial login support.
This commit is contained in:
parent
61b0066f0a
commit
1447b2fa6e
1
Build.PL
1
Build.PL
@ -31,6 +31,7 @@ my $build = Module::Build->new(
|
|||||||
'DBIx::Class' => 0,
|
'DBIx::Class' => 0,
|
||||||
'UUID::URandom' => 0,
|
'UUID::URandom' => 0,
|
||||||
'Crypt::Bcrypt' => 0,
|
'Crypt::Bcrypt' => 0,
|
||||||
|
'DBIx::Class::TimeStamp' => 0,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
$build->create_build_script;
|
$build->create_build_script;
|
||||||
|
@ -16,6 +16,9 @@ export default class Conquer {
|
|||||||
private conquerLoginGoToRegister: HTMLAnchorElement
|
private conquerLoginGoToRegister: HTMLAnchorElement
|
||||||
private conquerLoginError: HTMLParagraphElement
|
private conquerLoginError: HTMLParagraphElement
|
||||||
private conquerLoginSuccess: HTMLParagraphElement
|
private conquerLoginSuccess: HTMLParagraphElement
|
||||||
|
private conquerLoginUsername: HTMLInputElement
|
||||||
|
private conquerLoginPassword: HTMLInputElement
|
||||||
|
private conquerLoginSubmit: HTMLButtonElement
|
||||||
private conquerRegisterGoToLogin: HTMLAnchorElement
|
private conquerRegisterGoToLogin: HTMLAnchorElement
|
||||||
private conquerRegister: HTMLDivElement
|
private conquerRegister: HTMLDivElement
|
||||||
private conquerRegisterUsername: HTMLInputElement
|
private conquerRegisterUsername: HTMLInputElement
|
||||||
@ -73,7 +76,54 @@ export default class Conquer {
|
|||||||
Conquer.fail('Unable to find conquer login success.')
|
Conquer.fail('Unable to find conquer login success.')
|
||||||
}
|
}
|
||||||
this.conquerLoginSuccess = conquerLoginSuccess
|
this.conquerLoginSuccess = conquerLoginSuccess
|
||||||
|
const conquerLoginUsername = document.querySelector('.conquer-login-username')
|
||||||
|
if (conquerLoginUsername === null || !(conquerLoginUsername instanceof HTMLInputElement)) {
|
||||||
|
Conquer.fail('Unable to find conquer login username field.')
|
||||||
}
|
}
|
||||||
|
this.conquerLoginUsername = conquerLoginUsername
|
||||||
|
const conquerLoginPassword = document.querySelector('.conquer-login-password')
|
||||||
|
if (conquerLoginPassword === null || !(conquerLoginPassword instanceof HTMLInputElement)) {
|
||||||
|
Conquer.fail('Unable to find conquer login password field.')
|
||||||
|
}
|
||||||
|
this.conquerLoginPassword = conquerLoginPassword
|
||||||
|
const conquerLoginSubmit = document.querySelector('.conquer-login-submit')
|
||||||
|
if (conquerLoginSubmit === null || !(conquerLoginSubmit instanceof HTMLButtonElement)) {
|
||||||
|
Conquer.fail('Unable to find the submit button for the login.')
|
||||||
|
}
|
||||||
|
this.conquerLoginSubmit = conquerLoginSubmit
|
||||||
|
this.conquerLoginSubmit.addEventListener('click', () => {
|
||||||
|
this.onLoginRequested()
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async onLoginRequested(): Promise<void> {
|
||||||
|
const username = this.conquerLoginUsername.value;
|
||||||
|
const password = this.conquerLoginPassword.value;
|
||||||
|
const urlUser = new URL('/conquer/user/login', window.location.protocol + '//' + window.location.hostname + ':' + window.location.port)
|
||||||
|
let responseJson
|
||||||
|
let status
|
||||||
|
try {
|
||||||
|
const response = await fetch(urlUser, {
|
||||||
|
method: 'POST',
|
||||||
|
body: JSON.stringify({
|
||||||
|
username: username,
|
||||||
|
password: password,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
responseJson = await response.json()
|
||||||
|
status = response.status
|
||||||
|
} catch(e) {
|
||||||
|
console.error(e)
|
||||||
|
this.addNewLoginError('El servidor ha enviado datos inesperados.')
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (status !== 200) {
|
||||||
|
this.addNewLoginError(responseJson.error)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.unsetLoginAndRegisterErrors()
|
||||||
|
}
|
||||||
|
|
||||||
async goToRegister(): Promise<void> {
|
async goToRegister(): Promise<void> {
|
||||||
const isLogged = await this.isLogged();
|
const isLogged = await this.isLogged();
|
||||||
await this.removeLoginRegisterCombo()
|
await this.removeLoginRegisterCombo()
|
||||||
@ -150,6 +200,9 @@ export default class Conquer {
|
|||||||
const password = this.conquerRegisterPassword.value
|
const password = this.conquerRegisterPassword.value
|
||||||
const repeatPassword = this.conquerRegisterRepeatPassword.value
|
const repeatPassword = this.conquerRegisterRepeatPassword.value
|
||||||
const urlUser = new URL('/conquer/user', window.location.protocol + '//' + window.location.hostname + ':' + window.location.port)
|
const urlUser = new URL('/conquer/user', window.location.protocol + '//' + window.location.hostname + ':' + window.location.port)
|
||||||
|
let responseJson
|
||||||
|
let status
|
||||||
|
try {
|
||||||
const response = await fetch(urlUser, {
|
const response = await fetch(urlUser, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
body: JSON.stringify({
|
body: JSON.stringify({
|
||||||
@ -158,14 +211,14 @@ export default class Conquer {
|
|||||||
repeat_password: repeatPassword
|
repeat_password: repeatPassword
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
let responseJson
|
|
||||||
try {
|
|
||||||
responseJson = await response.json()
|
responseJson = await response.json()
|
||||||
|
status = response.status
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.error(e)
|
console.error(e)
|
||||||
|
this.addNewRegisterError('El servidor ha enviado datos inesperados.')
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (response.status !== 200) {
|
if (status !== 200) {
|
||||||
this.addNewRegisterError(responseJson.error)
|
this.addNewRegisterError(responseJson.error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -178,6 +231,12 @@ export default class Conquer {
|
|||||||
this.conquerLoginSuccess.classList.remove('conquer-display-none')
|
this.conquerLoginSuccess.classList.remove('conquer-display-none')
|
||||||
|
|
||||||
}
|
}
|
||||||
|
addNewLoginError(error: string): void {
|
||||||
|
this.unsetLoginAndRegisterErrors()
|
||||||
|
this.conquerLoginSuccess.classList.add('conquer-display-none')
|
||||||
|
this.conquerLoginError.innerText = error
|
||||||
|
this.conquerLoginError.classList.remove('conquer-display-none')
|
||||||
|
}
|
||||||
addNewRegisterError(error: string): void {
|
addNewRegisterError(error: string): void {
|
||||||
this.unsetLoginAndRegisterErrors()
|
this.unsetLoginAndRegisterErrors()
|
||||||
this.conquerLoginSuccess.classList.add('conquer-display-none')
|
this.conquerLoginSuccess.classList.add('conquer-display-none')
|
||||||
|
@ -52,6 +52,7 @@ sub startup ($self) {
|
|||||||
$r->get('/stats')->to('Metrics#stats');
|
$r->get('/stats')->to('Metrics#stats');
|
||||||
$r->get('/conquer')->to('Conquer#index');
|
$r->get('/conquer')->to('Conquer#index');
|
||||||
$r->put('/conquer/user')->to('UserConquer#create');
|
$r->put('/conquer/user')->to('UserConquer#create');
|
||||||
|
$r->post('/conquer/user/login')->to('UserConquer#login');
|
||||||
$r->get('/search.json')->to('Search#search');
|
$r->get('/search.json')->to('Search#search');
|
||||||
$r->get('/farmacia-guardia.json')->to('FarmaciaGuardia#current');
|
$r->get('/farmacia-guardia.json')->to('FarmaciaGuardia#current');
|
||||||
$r->get('/<:category>.rss')->to('Page#category_rss');
|
$r->get('/<:category>.rss')->to('Page#category_rss');
|
||||||
|
@ -89,8 +89,6 @@ sub submit_login {
|
|||||||
$self->render( text => 'Server error.', status => 500 );
|
$self->render( text => 'Server error.', status => 500 );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
say $password;
|
|
||||||
say $bcrypted_pass;
|
|
||||||
if ( !bcrypt_check( $password, $bcrypted_pass ) ) {
|
if ( !bcrypt_check( $password, $bcrypted_pass ) ) {
|
||||||
$self->render( text => 'Wrong password', status => 401 );
|
$self->render( text => 'Wrong password', status => 401 );
|
||||||
return;
|
return;
|
||||||
|
@ -12,6 +12,7 @@ use Mojo::Base 'Mojolicious::Controller', '-signatures';
|
|||||||
use UUID::URandom qw/create_uuid_string/;
|
use UUID::URandom qw/create_uuid_string/;
|
||||||
use Crypt::Bcrypt qw/bcrypt bcrypt_check/;
|
use Crypt::Bcrypt qw/bcrypt bcrypt_check/;
|
||||||
use Crypt::URandom qw/urandom/;
|
use Crypt::URandom qw/urandom/;
|
||||||
|
use JSON;
|
||||||
|
|
||||||
use BurguillosInfo::Schema;
|
use BurguillosInfo::Schema;
|
||||||
|
|
||||||
@ -21,18 +22,56 @@ my $password_minimum_chars = 8;
|
|||||||
my $password_maximum_chars = 4096;
|
my $password_maximum_chars = 4096;
|
||||||
|
|
||||||
sub create ($self) {
|
sub create ($self) {
|
||||||
my $input;
|
my $input = $self->_expectJson;
|
||||||
eval { $input = $self->req->json; };
|
if ( !defined $input ) {
|
||||||
if ($@) {
|
return;
|
||||||
say STDERR $@;
|
|
||||||
return $self->render( text => 'Expecting json', status => 400 );
|
|
||||||
}
|
}
|
||||||
my $username = $input->{username};
|
my $username = $input->{username};
|
||||||
my $password = $input->{password};
|
my $password = $input->{password};
|
||||||
my $repeat_password = $input->{repeat_password};
|
my $repeat_password = $input->{repeat_password};
|
||||||
return
|
return
|
||||||
unless $self->_createCheckInput( $username, $password, $repeat_password );
|
unless $self->_createCheckInput( $username, $password, $repeat_password );
|
||||||
return $self->_createUser($username, $password);
|
return $self->_createUser( $username, $password );
|
||||||
|
}
|
||||||
|
|
||||||
|
sub _expectJson ($self) {
|
||||||
|
my $input;
|
||||||
|
eval { $input = $self->req->json; };
|
||||||
|
if ($@) {
|
||||||
|
say STDERR $@;
|
||||||
|
$self->_renderError(400, 'Se esperaba JSON.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return $input;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub login ($self) {
|
||||||
|
my $input = $self->_expectJson;
|
||||||
|
if ( !defined $input ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
my $username = $input->{username};
|
||||||
|
my $password = $input->{password};
|
||||||
|
|
||||||
|
my $resultset_conquer_user =
|
||||||
|
BurguillosInfo::Schema->Schema->resultset('ConquerUser');
|
||||||
|
my @tentative_users =
|
||||||
|
$resultset_conquer_user->search( { username => $username } );
|
||||||
|
my $tentative_user = $tentative_users[0];
|
||||||
|
if (!defined $tentative_user) {
|
||||||
|
$self->_renderError(401, 'El usuario especificado no existe.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ( !bcrypt_check( $password, $tentative_user->encrypted_password ) ) {
|
||||||
|
$self->_renderError( 401, 'Contraseña incorrecta.' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
success => $JSON::true
|
||||||
|
},
|
||||||
|
status => 200
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
sub _createUser ( $self, $username, $password ) {
|
sub _createUser ( $self, $username, $password ) {
|
||||||
@ -52,19 +91,19 @@ sub _createUser ( $self, $username, $password ) {
|
|||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
if ( $@ =~ /Key \((.*?)\)=\((.*?)\) already exists\./ ) {
|
if ( $@ =~ /Key \((.*?)\)=\((.*?)\) already exists\./ ) {
|
||||||
return $self->renderError( 400,
|
return $self->_renderError( 400,
|
||||||
"The key $1 ($2) already exists in the database.",
|
"La clave $1 ($2) ya existe en la base de datos.",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
say STDERR $@;
|
say STDERR $@;
|
||||||
return $self->renderError( 400,
|
return $self->_renderError( 400,
|
||||||
'No se pudo crear el usuario por razones desconocidas.' );
|
'No se pudo crear el usuario por razones desconocidas.' );
|
||||||
}
|
}
|
||||||
$self->render(status => 200, json => $user->serialize_to_owner);
|
$self->render( status => 200, json => $user->serialize_to_owner );
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub renderError ( $self, $status, $message ) {
|
sub _renderError ( $self, $status, $message ) {
|
||||||
$self->render( status => $status, json => { error => $message } );
|
$self->render( status => $status, json => { error => $message } );
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -75,7 +114,7 @@ sub _createCheckInput ( $self, $username, $password, $repeat_password ) {
|
|||||||
/^(?:\w|\d|[ÑÁÉÍÓÚñáéíóú ]){$username_minimum_chars,$username_maximum_chars}$/
|
/^(?:\w|\d|[ÑÁÉÍÓÚñáéíóú ]){$username_minimum_chars,$username_maximum_chars}$/
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return $self->renderError( 400,
|
return $self->_renderError( 400,
|
||||||
"Username invalido, las reglas son tamaño entre $username_minimum_chars y $username_maximum_chars"
|
"Username invalido, las reglas son tamaño entre $username_minimum_chars y $username_maximum_chars"
|
||||||
. ' carácteres y solo se podrán usar letras, números y espacios.'
|
. ' carácteres y solo se podrán usar letras, números y espacios.'
|
||||||
);
|
);
|
||||||
@ -85,7 +124,7 @@ sub _createCheckInput ( $self, $username, $password, $repeat_password ) {
|
|||||||
|| $password !~ /^.{$password_minimum_chars,$password_maximum_chars}$/
|
|| $password !~ /^.{$password_minimum_chars,$password_maximum_chars}$/
|
||||||
|| $password =~ /^\d+$/ )
|
|| $password =~ /^\d+$/ )
|
||||||
{
|
{
|
||||||
return $self->renderError(
|
return $self->_renderError(
|
||||||
400,
|
400,
|
||||||
'Contraseña invalida, las reglas son la contraseña debe ser'
|
'Contraseña invalida, las reglas son la contraseña debe ser'
|
||||||
. ' distinta al nombre de usuario, la contraseña debe tener entre'
|
. ' distinta al nombre de usuario, la contraseña debe tener entre'
|
||||||
@ -96,7 +135,7 @@ sub _createCheckInput ( $self, $username, $password, $repeat_password ) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if ( !defined $repeat_password || $password ne $repeat_password ) {
|
if ( !defined $repeat_password || $password ne $repeat_password ) {
|
||||||
$self->renderError(
|
$self->_renderError(
|
||||||
400,
|
400,
|
||||||
'El campo de repetir contraseña debe coincidir de forma'
|
'El campo de repetir contraseña debe coincidir de forma'
|
||||||
. ' totalmente exacta con el campo de contraseña para asegurar'
|
. ' totalmente exacta con el campo de contraseña para asegurar'
|
||||||
|
@ -53,10 +53,10 @@ sub MIGRATIONS {
|
|||||||
uuid UUID NOT NULL PRIMARY KEY,
|
uuid UUID NOT NULL PRIMARY KEY,
|
||||||
username TEXT NOT NULL UNIQUE,
|
username TEXT NOT NULL UNIQUE,
|
||||||
encrypted_password TEXT NOT NULL,
|
encrypted_password TEXT NOT NULL,
|
||||||
last_activity TEXT NOT NULL DEFAULT NOW(),
|
last_activity TIMESTAMP NOT NULL DEFAULT NOW(),
|
||||||
is_admin boolean NOT NULL DEFAULT false
|
is_admin BOOLEAN NOT NULL DEFAULT false,
|
||||||
|
registration_date TIMESTAMP NOT NULL DEFAULT NOW()
|
||||||
);',
|
);',
|
||||||
'ALTER TABLE conquer_user ADD COLUMN registration_date TIMESTAMP NOT NULL DEFAULT NOW();',
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ use parent 'DBIx::Class::Core';
|
|||||||
use feature 'signatures';
|
use feature 'signatures';
|
||||||
|
|
||||||
__PACKAGE__->table('conquer_user');
|
__PACKAGE__->table('conquer_user');
|
||||||
|
__PACKAGE__->load_components("TimeStamp");
|
||||||
|
|
||||||
__PACKAGE__->add_columns(
|
__PACKAGE__->add_columns(
|
||||||
uuid => {
|
uuid => {
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user