Improve readme and allow password changing.

This commit is contained in:
Citlali del Rey 2023-02-22 22:23:38 -08:00
parent 5bb8febfa2
commit 9a47d097bf
Signed by: nullobsi
GPG Key ID: 933A1F44222C2634
6 changed files with 75 additions and 12 deletions

View File

@ -2,11 +2,6 @@
Simple IPFS remote pinning service and
HTTP upload provider.
Currently, it only supports Postgres and LDAP
as backends. LDAP is used to login while Postgres
is used to store information about pins and access tokens
used by tools.
In addition to providing a remote pinning endpoint
at /api, you can also POST uploads directly to the
root `/` with an access token and recieve a URL back:
@ -17,8 +12,8 @@ https://unix.dog/ipfs/Qm...
## Setup
To setup this service locally, you will need:
- PostgreSQL
- LDAP service with password auth
- PostgreSQL (optional)
- LDAP service with password auth (optional)
- IPFS node with RPC API (Kubo)
Copy the config ipfs_upload.default.yml to
@ -26,3 +21,12 @@ ipfs_upload.yml, and edit the config appropriately.
Then use hypnotoad or morbo to run `script/IpfsUpload`.
Log in, generate tokens, and point your IPFS remote pinning
to /api. Done!
## Databases
IPFS Upload supports PostgreSQL or SQLite. LDAP and in-database
password hashing with Argon2ID are also supported. Check the default
config to learn how to configure it properly.
When using in-database authentication, you can change your password
on the Access Token page. In the config, you can whitelist usernames.
The password will be set on first login.

View File

@ -70,6 +70,7 @@ sub startup($self) {
$r->get('/login')->to('Login#login');
$r->get('/my/logout')->to('Login#logout');
$r->post('/auth')->to('Login#auth');
$r->post('/my/password')->to('Login#change_password');
$r->get('/my')->to('Interface#landing');
$r->get('/my/tokens')->to('Interface#token_list');

View File

@ -31,7 +31,7 @@ sub auth($c) {
my $mesg = $ldap->bind($bindDN, password=>$password);
$mesg->code and die $mesg->error;
})->then(sub ($res) {
return $c->users->getOrMake($username);
return $c->users->get_or_make($username);
})->then(sub ($res) {
$c->session->{uid} = $res;
$c->flash(msg => "Logged in.");
@ -41,11 +41,26 @@ sub auth($c) {
$c->redirect_to('/login');
});
} elsif ($config->{auth} eq 'db') {
# Check if whitelisted
if (not grep $_ eq $username, @{$config->{whitelist_names}}) {
$c->flash(msg => "Login failed.");
return $c->redirect_to('/login');
}
# Attempt to get user from username
return $c->users->get($username)->then(sub ($uid) {
# Create if not exists
if (!defined $uid) {
$c->flash(msg => "Login failed.");
return $c->redirect_to('/login');
# Hash pass + insert and create user
my $hash = IpfsUpload::Util::add_pass($password);
return $c->users->make_with_pass($username, $hash)->then(sub ($uid_new) {
$c->session->{uid} = $uid_new;
$c->flash(msg => "Logged in.");
return $c->redirect_to('/my');
});
}
# Verify password
return $c->users->get_pass_hash($uid)->then(sub ($hash) {
if (IpfsUpload::Util::check_pass($password, $hash)) {
$c->session->{uid} = $uid;
@ -55,6 +70,7 @@ sub auth($c) {
die "Login failed.";
});
})->catch(sub ($err) {
say $err;
$c->flash(msg => "Login failed.");
$c->redirect_to('/login');
});
@ -73,4 +89,25 @@ sub logout($c) {
return $c->redirect_to('/login');
}
sub change_password($c) {
if (!IpfsUpload::Util::check_auth($c)) {
return $c->redirect_to("/login");
}
if ($c->config->{auth} ne 'db') {
return $c->redirect_to('/my');
}
my $uid = $c->stash('uid');
my $v = $c->validation;
$v->required('password');
return $c->redirect_to('/my') if $v->has_error;
my $password = $c->param('password');
return $c->users->set_pass_hash($uid, IpfsUpload::Util::add_pass($password))->then(sub {
$c->flash(msg => "Password set.");
return $c->redirect_to('/my');
});
}
1;

View File

@ -57,7 +57,7 @@ sub list_tokens($self, $uid) {
});
}
sub getOrMake($self, $username) {
sub get_or_make($self, $username) {
return $self->sql->db->select_p('users', ['uid'], {username => $username})->then(sub ($res) {
my $val = $res->hash;
if (defined $val) {
@ -85,4 +85,13 @@ sub get_pass_hash($self, $uid) {
});
}
sub make_with_pass($self, $username, $hash) {
return $self->sql->db->insert_p('users', {username => $username, pass => $hash}, {returning => 'uid'})->then(sub ($n) {
return $n->hash->{uid};
});
}
sub set_pass_hash($self, $uid, $hash) {
return $self->sql->db->update_p('users', { pass => $hash }, { uid => $uid });
}
1;

View File

@ -11,7 +11,7 @@ use Bytes::Random::Secure qw/random_bytes_hex/;
sub add_pass($pass) {
my $salt = random_bytes_hex(16);
my $encoded = argon2id_pass($pass, $salt, '32M', 1, 16);
my $encoded = argon2id_pass($pass, $salt, 3, '32M', 1, 16);
return $encoded;
}

View File

@ -45,3 +45,15 @@
<p>
<a href="https://docs.ipfs.tech/how-to/work-with-pinning-services/">More info on pinning</a>
</p>
% if ($c->config->{auth} eq 'db') {
<p>Change your password here:</p>
%= form_for '/my/password' => (method => 'POST') => begin
<p>
%= label_for password => 'New Password'
%= password_field 'password', id=>'password'
</p>
%= submit_button
% end
% }