7 changed files with 362 additions and 21 deletions
+1
View File
@@ -4,3 +4,4 @@ links.db
launch.json launch.json
settings.json settings.json
links.session.sql links.session.sql
sqltemplates
Generated
+9 -1
View File
@@ -1048,6 +1048,9 @@ name = "either"
version = "1.6.1" version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
@@ -2174,7 +2177,7 @@ dependencies = [
[[package]] [[package]]
name = "pslink" name = "pslink"
version = "0.3.0" version = "0.3.1"
dependencies = [ dependencies = [
"actix-identity", "actix-identity",
"actix-slog", "actix-slog",
@@ -2694,6 +2697,7 @@ version = "1.0.61"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a" checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
dependencies = [ dependencies = [
"indexmap",
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",
@@ -2887,6 +2891,7 @@ dependencies = [
"parking_lot", "parking_lot",
"percent-encoding", "percent-encoding",
"rustls", "rustls",
"serde",
"sha2", "sha2",
"smallvec", "smallvec",
"sqlformat", "sqlformat",
@@ -2910,9 +2915,12 @@ dependencies = [
"either", "either",
"futures 0.3.12", "futures 0.3.12",
"heck", "heck",
"hex",
"lazy_static", "lazy_static",
"proc-macro2 1.0.24", "proc-macro2 1.0.24",
"quote 1.0.8", "quote 1.0.8",
"serde",
"serde_json",
"sha2", "sha2",
"sqlx-core", "sqlx-core",
"sqlx-rt", "sqlx-rt",
+3 -3
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "pslink" name = "pslink"
version = "0.3.0" version = "0.3.1"
description = "A simple webservice that allows registered users to create short links including qr-codes.\nAnyone can visit the shortened links. This is an ideal setup for small busines or for publishing papers." description = "A simple webservice that allows registered users to create short links including qr-codes.\nAnyone can visit the shortened links. This is an ideal setup for small busines or for publishing papers."
authors = ["Dietrich <dietrich@teilgedanken.de>"] authors = ["Dietrich <dietrich@teilgedanken.de>"]
edition = "2018" edition = "2018"
@@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0"
keywords = ["url", "link", "webpage", "actix", "web"] keywords = ["url", "link", "webpage", "actix", "web"]
categories = ["web-programming", "network-programming", "web-programming::http-server", "command-line-utilities"] categories = ["web-programming", "network-programming", "web-programming::http-server", "command-line-utilities"]
readme = "README.md" readme = "README.md"
repository = "https://git.teilgedanken.de/dietrich/Pslink" repository = "https://github.com/enaut/pslink/"
build = "build.rs" build = "build.rs"
@@ -20,7 +20,7 @@ actix-web-static-files = "3.0"
actix-slog = "0.2" actix-slog = "0.2"
tera = "1.6" tera = "1.6"
serde = "1.0" serde = "1.0"
sqlx={version="0.4", features = [ "sqlite", "macros", "runtime-actix-rustls", "chrono", "migrate" ]} sqlx={version="0.4", features = [ "sqlite", "macros", "runtime-actix-rustls", "chrono", "migrate", "offline" ]}
dotenv = "0.15.0" dotenv = "0.15.0"
actix-identity = "0.3" actix-identity = "0.3"
chrono = { version = "0.4", features = ["serde"] } chrono = { version = "0.4", features = ["serde"] }
+66 -16
View File
@@ -2,41 +2,91 @@
The target audience of this tool are small entities that need a url shortener. The shortened urls can be publicly resolved but only registered users can create short urls. Every registered user can see all shorted urls but ownly modify its own. Admin users can invite other accounts and edit everything that can be edited (also urls created by other accounts). The target audience of this tool are small entities that need a url shortener. The shortened urls can be publicly resolved but only registered users can create short urls. Every registered user can see all shorted urls but ownly modify its own. Admin users can invite other accounts and edit everything that can be edited (also urls created by other accounts).
So in general this is more a shared short url bookmark webpage than a shorturl service.
![Screenshot](./doc/img/pslinkscreenshot.png) ![Screenshot](./doc/img/pslinkscreenshot.png)
The Page comes with a basic commandline interface to setup the environment. If it is built with `cargo build release --target=x86_64-unknown-linux-musl` everything is embedded and it should be portable to any 64bit linux system. The Page comes with a basic commandline interface to setup the environment.
Templates and migrations are embedded in the binary. So it should run standalone without anything extra.
## usage ## Usage
### setup ### install binary
The pslink binary can be downloaded from the latest release at: https://github.com/enaut/pslink/releases
These binaries are selfcontained and should run on any linux 64bit system. Just put them where you like them to be and make them executable. A sample install might be:
```bash
# mkdir -p /opt/pslink
# wget -o /opt/pslink/pslink https://github.com/enaut/pslink/releases/latest/download/pslink.linux.64bit
# chmod +x /opt/pslink/pslink
```
You could now adjust your `PATH` or setup an alias or just call the binary with the full path `/opt/pslink/pslink`
### Install with cargo
Pslink can be compiled and installed with cargo. Setup cargo as guided here: https://doc.rust-lang.org/cargo/getting-started/installation.html
After that install pslink using:
```bash
$ cargo install pslink
```
If that succeeds you should now be able to call pslink.
### Build from source
When building manually with cargo you have to have a sqlite database present or build it in offline mode. So on your first build you will most likely need to call:
```bash
SQLX_OFFLINE=1 cargo run
# or
$ export SQLX_OFFLINE=1
$ cargo run
```
If pslink is built with `cargo build release --target=x86_64-unknown-linux-musl` everything is embedded and it should be portable to any 64bit linux system.
Templates and migrations are embedded in the binary so it should run standalone without anything extra.
### Setup
To get Pslink up and running use the commands in the following order: To get Pslink up and running use the commands in the following order:
1. `pslink generate-env` this will generate a `.env` file in the curent directory with the default settings. Edit this file to your liking. You can however skip this step and provide all the parameters via commandline or environmentvariable. It is **not** recommended to provide PSLINK_SECRET with commandline parameters as they can be read by every user on the system. 1. `pslink generate-env`
2. `pslink migrate-database` will create a sqlite database in the location specified.
3. `pslink create-admin` create an initial admin user. As the page has no "register" function this is required to do anything usefull.
4. `pslink runserver` If everything is set up correctly this command will start the service.
### run the service this will generate a `.env` file in the curent directory with the default settings. Edit this file to your liking. You can however skip this step and provide all the parameters via commandline or environmentvariable. It is **not** recommended to provide PSLINK_SECRET with commandline parameters as they can be read by every user on the system.
2. `pslink migrate-database`
will create a sqlite database in the location specified.
3. `pslink create-admin`
create an initial admin user. As the page has no "register" function this is required to do anything usefull.
4. `pslink runserver`
If everything is set up correctly this command will start the service.
### Run the service
If everything is correctly set up just do `pslink runserver`. If everything is correctly set up just do `pslink runserver`.
### update ### Update
To update to a newer version execute the commands in the following order To update to a newer version execute the commands in the following order
1. stop the service 1. stop the service
2. run `pslink migrate-database` 2. download and install the new binary
3. run the server again `pslink runserver` 3. run `pslink migrate-database`
4. run the server again `pslink runserver`
### help ### Help
For a list of options use `pslink help`. For a list of options use `pslink help`. If the help does not provide enough clues please file an issue at: https://github.com/enaut/pslink/issues/new
### systemd service file ### Systemd service file
If you want to automatically start this with systemd you can adjust the following template unit to your system. In this case a dedicated `pslink` user and group are used with the users home directory at `/var/pslink`. Some additional settings are in place to protect the system a little should anything go wrong. If you want to automatically start this with systemd you can adjust the following template unit to your system. In this case a dedicated `pslink` user and group is used with the users home directory at `/var/pslink`. Some additional settings are in place to protect the system a little should anything go wrong.
```systemd ```systemd
# /etc/systemd/system/pslink.service # /etc/systemd/system/pslink.service
+18
View File
@@ -0,0 +1,18 @@
Guide to release:
- [ ] Verify everything is committed
- [ ] update the sqlx cache: cargo sqlx prepare
- [ ] commit the update
- [ ] push to github and teilgedanken
- [ ] create release draft tag: https://github.com/enaut/pslink/releases
- [ ] verify everything is ready for publishing using:
```
SQLX_OFFLINE=1 cargo publish --dry-run
```
- [ ] make draft a release
- [ ] publish
```SQLX_OFFLINE=1 cargo publish```
+265
View File
@@ -0,0 +1,265 @@
{
"db": "SQLite",
"01e68928ea67ef301d8ea72a320fe747dafbfaa398a22731effb93d23ae16a77": {
"query": "UPDATE links SET\n title = ?,\n target = ?,\n code = ?,\n author = ?,\n created_at = ? where id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 6
},
"nullable": []
}
},
"04640e79c590ae8b845b6281a786ebe72060d02ee98eaec4839d1525bde3b0b5": {
"query": "Select * from links where code = ? ",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Int64"
},
{
"name": "title",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "target",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "code",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "author",
"ordinal": 4,
"type_info": "Int64"
},
{
"name": "created_at",
"ordinal": 5,
"type_info": "Datetime"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false,
false
]
}
},
"0d5cc1ab073e15c4306ef2bfc89aeefd6daa409766741c21f9eb0115b0f24eb1": {
"query": "UPDATE users SET\n username = ?,\n email = ?,\n password = ?,\n role = ? where id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
}
},
"109ddc9fa55a36541ed1a866d362ff666bb39c3672f72000e786f86b514dc239": {
"query": "Select * from users where id = ? ",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Int64"
},
{
"name": "username",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "email",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "password",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "role",
"ordinal": 4,
"type_info": "Int64"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false
]
}
},
"193ebdfd8bdb96da45f5054f83a6a5e23eaa311e3e5c4139095a3455f4764c64": {
"query": "Select * from users",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Int64"
},
{
"name": "username",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "email",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "password",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "role",
"ordinal": 4,
"type_info": "Int64"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false,
false,
false,
false,
false
]
}
},
"3ad5584fcb0c2685339e471320e8d0c091b684ffe86912a1f2540eee1444889d": {
"query": "Insert into clicks (\n link,\n created_at) VALUES (?,?)",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
}
},
"5919b8824209c31a76178f30b3d52f385931ee0f3aa17e65f8647ad15a3595d8": {
"query": "Insert into links (\n title,\n target,\n code,\n author,\n created_at) VALUES (?,?,?,?,?)",
"describe": {
"columns": [],
"parameters": {
"Right": 5
},
"nullable": []
}
},
"5d892d21ed6b4ccc3ddedb3a7469385f001f6ff9f41b19faa67b754ad8f7fc4b": {
"query": "Insert into users (\n username,\n email,\n password,\n role) VALUES (?,?,?,1)",
"describe": {
"columns": [],
"parameters": {
"Right": 3
},
"nullable": []
}
},
"77a21769284cb3df457d806d6e04088ae4f99d92c535fd15c79828e46ee3ae6f": {
"query": "UPDATE users SET role = ? where id = ?",
"describe": {
"columns": [],
"parameters": {
"Right": 2
},
"nullable": []
}
},
"7a52eae6cb72e4daac95a99d15113ab09571329733ea121fecc55d18dfdb1c45": {
"query": "DELETE from links where code = ? ",
"describe": {
"columns": [],
"parameters": {
"Right": 1
},
"nullable": []
}
},
"8670a2dacd013de68831d0a45d927ea9f473d86100387fc85c9b9802668c3de4": {
"query": "Select * from users where username = ? ",
"describe": {
"columns": [
{
"name": "id",
"ordinal": 0,
"type_info": "Int64"
},
{
"name": "username",
"ordinal": 1,
"type_info": "Text"
},
{
"name": "email",
"ordinal": 2,
"type_info": "Text"
},
{
"name": "password",
"ordinal": 3,
"type_info": "Text"
},
{
"name": "role",
"ordinal": 4,
"type_info": "Int64"
}
],
"parameters": {
"Right": 1
},
"nullable": [
false,
false,
false,
false,
false
]
}
},
"9cb2f491eab760ba60ede5b3e730b84d061fc09627579ff05bc63d3e27fe8fb7": {
"query": "select count(*) as number from users where role = 2",
"describe": {
"columns": [
{
"name": "number",
"ordinal": 0,
"type_info": "Int"
}
],
"parameters": {
"Right": 0
},
"nullable": [
false
]
}
}
}
-1
View File
@@ -157,7 +157,6 @@ pub(crate) async fn get_user(
if let Ok(uid) = user_id.parse::<i64>() { if let Ok(uid) = user_id.parse::<i64>() {
slog_info!(server_config.log, "Getting user {}", uid); slog_info!(server_config.log, "Getting user {}", uid);
let auth = authenticate(id, server_config).await?; let auth = authenticate(id, server_config).await?;
slog_info!(server_config.log, "{:?}", &auth);
if auth.admin_or_self(uid) { if auth.admin_or_self(uid) {
match auth { match auth {
Role::Admin { user } | Role::Regular { user } => { Role::Admin { user } | Role::Regular { user } => {