Compare commits
No commits in common. "master" and "min-libconductor" have entirely different histories.
master
...
min-libcon
42 changed files with 416 additions and 1879 deletions
|
@ -1,3 +0,0 @@
|
|||
/target
|
||||
.env.local
|
||||
tarpaulin-report.html
|
|
@ -1,5 +1,5 @@
|
|||
steps:
|
||||
test:
|
||||
pipeline:
|
||||
backend:
|
||||
image: rust
|
||||
# environment:
|
||||
# - DATABASE_URL=postgres://postgres:password@database:5432/postgres
|
||||
|
@ -7,30 +7,14 @@ steps:
|
|||
# - make migrate
|
||||
- make
|
||||
- make test
|
||||
- make release
|
||||
|
||||
publish_bins:
|
||||
image: rust
|
||||
when:
|
||||
event: [push, tag, deployment]
|
||||
branch: master
|
||||
commands:
|
||||
- apt update
|
||||
- apt-get -y --no-install-recommends install gpg tar curl wget
|
||||
- echo -n "$RELEASE_BOT_GPG_SIGNING_KEY" | gpg --batch --import --pinentry-mode loopback
|
||||
- ./scripts/bin-publish.sh publish master latest $DUMBSERVE_PASSWORD
|
||||
secrets: [ RELEASE_BOT_GPG_SIGNING_KEY, DUMBSERVE_PASSWORD, GPG_PASSWORD ]
|
||||
|
||||
publish:
|
||||
image: plugins/docker
|
||||
when:
|
||||
event: [push, tag, deployment]
|
||||
branch: master
|
||||
settings:
|
||||
username: realaravinth
|
||||
password:
|
||||
from_secret: DOCKER_TOKEN
|
||||
repo: realaravinth/librepages-conductor
|
||||
repo: realaravinth/librepages-forms
|
||||
tags: latest
|
||||
|
||||
#services:
|
||||
|
|
1201
Cargo.lock
generated
1201
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
13
Cargo.toml
13
Cargo.toml
|
@ -12,23 +12,18 @@ build = "build.rs"
|
|||
|
||||
[dependencies]
|
||||
actix-web = "4"
|
||||
actix-web-prom = "0.8.0"
|
||||
futures-util = { version = "0.3.17", default-features = false, features = ["std"] }
|
||||
lazy_static = "1.4.0"
|
||||
log = "0.4.17"
|
||||
pretty_env_logger = "0.5.0"
|
||||
pretty_env_logger = "0.4.0"
|
||||
serde = { version = "1", features=["derive"]}
|
||||
actix-web-codegen-const-routes = { version = "0.1.0", tag = "0.1.0", git = "https://github.com/realaravinth/actix-web-codegen-const-routes" }
|
||||
libconfig = { version = "0.1.0", git = "https://git.batsense.net/librepages/libconfig" }
|
||||
derive_builder = "0.20.0"
|
||||
config = "0.14"
|
||||
derive_builder = "0.11.2"
|
||||
config = "0.11"
|
||||
derive_more = "0.99.17"
|
||||
url = { version = "2.2.2", features = ["serde"]}
|
||||
serde_json = { version ="1", features = ["raw_value"]}
|
||||
clap = { vesrion = "3.2.20", features = ["derive"]}
|
||||
actix-web-httpauth = "0.8.0"
|
||||
mime_guess = "2.0.4"
|
||||
rust-embed = "8.0.0"
|
||||
|
||||
[dependencies.libconductor]
|
||||
path = "./env/libconductor"
|
||||
|
@ -42,4 +37,4 @@ sqlx = { version = "0.6.1", features = [ "runtime-actix-rustls", "postgres", "ti
|
|||
|
||||
[dev-dependencies]
|
||||
actix-rt = "2.7.0"
|
||||
base64 = "0.22.0"
|
||||
base64 = "0.13.0"
|
||||
|
|
|
@ -19,7 +19,7 @@ RUN cargo --version
|
|||
#RUN make cache-bust
|
||||
RUN cargo build --release
|
||||
|
||||
FROM debian:bookworm as conductor
|
||||
FROM debian:bullseye as conductor
|
||||
LABEL org.opencontainers.image.source https://git.batsense.net/librepages/conductor
|
||||
RUN apt-get update && apt-get install -y ca-certificates
|
||||
RUN useradd -ms /bin/bash -u 1001 conductor
|
||||
|
|
19
Makefile
19
Makefile
|
@ -1,12 +1,3 @@
|
|||
define lint
|
||||
cargo fmt -v --all -- --emit files
|
||||
cargo clippy --workspace --tests --all-features
|
||||
endef
|
||||
|
||||
define test
|
||||
cargo test --no-fail-fast --workspace --tests --all-features
|
||||
endef
|
||||
|
||||
default: ## Build app in debug mode
|
||||
cargo build
|
||||
|
||||
|
@ -34,9 +25,8 @@ env: ## Setup development environtment
|
|||
cargo fetch
|
||||
|
||||
lint: ## Lint codebase
|
||||
$(call lint)
|
||||
cd env/dummy_conductor && $(call lint)
|
||||
cd env/libconductor && $(call lint)
|
||||
cargo fmt -v --all -- --emit files
|
||||
cargo clippy --workspace --tests --all-features
|
||||
|
||||
#migrate: ## run migrations
|
||||
# unset DATABASE_URL && cargo build
|
||||
|
@ -46,7 +36,7 @@ release: ## Build app with release optimizations
|
|||
cargo build --release
|
||||
|
||||
run: ## Run app in debug mode
|
||||
cargo run -- serve
|
||||
cargo run
|
||||
|
||||
|
||||
#sqlx-offline-data: ## prepare sqlx offline data
|
||||
|
@ -55,8 +45,7 @@ run: ## Run app in debug mode
|
|||
# --all-features
|
||||
|
||||
test: ## Run all available tests
|
||||
$(call test)
|
||||
cd env/dummy_conductor && $(call test)
|
||||
cargo test --no-fail-fast --workspace
|
||||
|
||||
xml-test-coverage: ## Generate code coverage report in XML format
|
||||
cargo tarpaulin -t 1200 --out Xml
|
||||
|
|
|
@ -2,9 +2,6 @@ debug = true
|
|||
source_code = "https://git.batsense.net/librepages/conductor"
|
||||
conductor = "dummy"
|
||||
|
||||
[creds]
|
||||
token="longrandomlygeneratedpassword"
|
||||
|
||||
[server]
|
||||
# Please set a unique value, your mCaptcha instance's security depends on this being
|
||||
# unique
|
||||
|
@ -13,7 +10,7 @@ token="longrandomlygeneratedpassword"
|
|||
port = 7000
|
||||
#IP address. Enter 0.0.0.0 to listen on all available addresses
|
||||
#ip= "0.0.0.0"
|
||||
ip= "127.0.0.1"
|
||||
ip= "192.168.0.104"
|
||||
# enter your hostname, eg: example.com
|
||||
domain = "localhost"
|
||||
# Set true if you have setup TLS with a reverse proxy like Nginx.
|
|
@ -1,24 +0,0 @@
|
|||
[Unit]
|
||||
Description=LibrePages Conductor: Easiest way to deploy websites. Conductor component
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
ExecStart=/usr/bin/conductor serve
|
||||
Restart=on-failure
|
||||
RestartSec=1
|
||||
SuccessExitStatus=3 4
|
||||
RestartForceExitStatus=3 4
|
||||
SystemCallArchitectures=native
|
||||
MemoryDenyWriteExecute=true
|
||||
NoNewPrivileges=true
|
||||
Environment="RUST_LOG=info"
|
||||
|
||||
[Unit]
|
||||
Wants=network-online.target
|
||||
Wants=network-online.target
|
||||
Requires=postgresql.service
|
||||
After=syslog.target
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
Binary file not shown.
Before Width: | Height: | Size: 665 B |
Binary file not shown.
Before Width: | Height: | Size: 628 B |
|
@ -1,16 +0,0 @@
|
|||
html {
|
||||
box-sizing: border-box;
|
||||
overflow: -moz-scrollbars-vertical;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
*,
|
||||
*:before,
|
||||
*:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
background: #fafafa;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
<!-- HTML for static distribution bundle build -->
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>LibrePages Conductor | Swagger UI</title>
|
||||
<link rel="stylesheet" type="text/css" href="/docs/openapi/swagger-ui.css" />
|
||||
<link rel="stylesheet" type="text/css" href="/docs/openapi/index.css" />
|
||||
<link rel="icon" type="image/png" href="/docs/openapi/favicon-32x32.png" sizes="32x32" />
|
||||
<link rel="icon" type="image/png" href="/docs/openapi/favicon-16x16.png" sizes="16x16" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="swagger-ui"></div>
|
||||
<script src="/docs/openapi/swagger-ui-bundle.js" charset="UTF-8"> </script>
|
||||
<script src="/docs/openapi/swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
|
||||
<script src="/docs/openapi/swagger-initializer.js" charset="UTF-8"> </script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,79 +0,0 @@
|
|||
<!doctype html>
|
||||
<html lang="en-US">
|
||||
<head>
|
||||
<title>Swagger UI: OAuth2 Redirect</title>
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
'use strict';
|
||||
function run () {
|
||||
var oauth2 = window.opener.swaggerUIRedirectOauth2;
|
||||
var sentState = oauth2.state;
|
||||
var redirectUrl = oauth2.redirectUrl;
|
||||
var isValid, qp, arr;
|
||||
|
||||
if (/code|token|error/.test(window.location.hash)) {
|
||||
qp = window.location.hash.substring(1).replace('?', '&');
|
||||
} else {
|
||||
qp = location.search.substring(1);
|
||||
}
|
||||
|
||||
arr = qp.split("&");
|
||||
arr.forEach(function (v,i,_arr) { _arr[i] = '"' + v.replace('=', '":"') + '"';});
|
||||
qp = qp ? JSON.parse('{' + arr.join() + '}',
|
||||
function (key, value) {
|
||||
return key === "" ? value : decodeURIComponent(value);
|
||||
}
|
||||
) : {};
|
||||
|
||||
isValid = qp.state === sentState;
|
||||
|
||||
if ((
|
||||
oauth2.auth.schema.get("flow") === "accessCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorizationCode" ||
|
||||
oauth2.auth.schema.get("flow") === "authorization_code"
|
||||
) && !oauth2.auth.code) {
|
||||
if (!isValid) {
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "warning",
|
||||
message: "Authorization may be unsafe, passed state was changed in server. The passed state wasn't returned from auth server."
|
||||
});
|
||||
}
|
||||
|
||||
if (qp.code) {
|
||||
delete oauth2.state;
|
||||
oauth2.auth.code = qp.code;
|
||||
oauth2.callback({auth: oauth2.auth, redirectUrl: redirectUrl});
|
||||
} else {
|
||||
let oauthErrorMsg;
|
||||
if (qp.error) {
|
||||
oauthErrorMsg = "["+qp.error+"]: " +
|
||||
(qp.error_description ? qp.error_description+ ". " : "no accessCode received from the server. ") +
|
||||
(qp.error_uri ? "More info: "+qp.error_uri : "");
|
||||
}
|
||||
|
||||
oauth2.errCb({
|
||||
authId: oauth2.auth.name,
|
||||
source: "auth",
|
||||
level: "error",
|
||||
message: oauthErrorMsg || "[Authorization failed]: no accessCode received from the server."
|
||||
});
|
||||
}
|
||||
} else {
|
||||
oauth2.callback({auth: oauth2.auth, token: qp, isValid: isValid, redirectUrl: redirectUrl});
|
||||
}
|
||||
window.close();
|
||||
}
|
||||
|
||||
if (document.readyState !== 'loading') {
|
||||
run();
|
||||
} else {
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
run();
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,178 +0,0 @@
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: LibrePages Conductor - OpenAPI 3.0
|
||||
description: |-
|
||||
|
||||
Conductor is the deployment manager used internally in LibrePages. It is
|
||||
responsible for creating, updating and deleting websites that are deployed
|
||||
with LibrePages
|
||||
|
||||
Some useful links:
|
||||
- [LibrePages Conductor repository](https://git.batsense.net/LibrePages/conductor)
|
||||
termsOfService: http://libreapages.org/terms/
|
||||
contact:
|
||||
email: contact@libreapages.org
|
||||
license:
|
||||
name: AGPLv3 or later version
|
||||
url: https://www.gnu.org/licenses/agpl.html
|
||||
version: 0.1.0
|
||||
externalDocs:
|
||||
description: LibrePages Conductor - internal service to update deployments
|
||||
url: http://git.batsense.net/LibrePages/conductor
|
||||
|
||||
tags:
|
||||
- name: meta
|
||||
description: Information about the system
|
||||
- name: site
|
||||
description: Information about customer site deployments
|
||||
paths:
|
||||
/api/v1/events/new:
|
||||
post:
|
||||
tags:
|
||||
- site
|
||||
summary: Post new event to Conductor
|
||||
description: Conductor schedules jobs based on events posted to it.
|
||||
operationId: eventsNew
|
||||
responses:
|
||||
"201":
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: "#/components/schemas/eventsNewPayloadNewSite"
|
||||
- $ref: "#/components/schemas/eventsNewPayloadConfig"
|
||||
- $ref: "#/components/schemas/eventsNewPayloadDeleteSite"
|
||||
/api/v1/meta/build:
|
||||
get:
|
||||
tags:
|
||||
- meta
|
||||
summary: Get binary's build information
|
||||
description: Update an existing pet by Idinformation
|
||||
operationId: metaBuild
|
||||
responses:
|
||||
"200":
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/BuildInformation"
|
||||
/api/v1/meta/health:
|
||||
get:
|
||||
tags:
|
||||
- meta
|
||||
summary: Get instance's health information
|
||||
description: Get instance's health information
|
||||
operationId: metaHealth
|
||||
responses:
|
||||
"200":
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/HealthInformation"
|
||||
|
||||
|
||||
components:
|
||||
schemas:
|
||||
BuildInformation:
|
||||
required:
|
||||
- version
|
||||
- git_commit_hash
|
||||
- source_code
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
type: string
|
||||
example: v0.1.0
|
||||
git_commit_hash:
|
||||
type: string
|
||||
example: 1fa28ef9b70bb04d6c76eee9e9bc5be77005b4b0
|
||||
source_code:
|
||||
type: string
|
||||
example: https://git.batsense.net/LibrePages
|
||||
HealthInformation:
|
||||
required:
|
||||
- conductor
|
||||
type: object
|
||||
properties:
|
||||
conductor:
|
||||
type: boolean
|
||||
example: true
|
||||
|
||||
eventsNewPayloadConfig:
|
||||
type: object
|
||||
required:
|
||||
- data
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/LibConfigConfig'
|
||||
LibConfigConfig:
|
||||
properties:
|
||||
source:
|
||||
$ref: '#/components/schemas/LibConfigSource'
|
||||
forms:
|
||||
$ref: '#/components/schemas/LibConfigForms'
|
||||
domains:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: ["example.com", "testing.example.org"]
|
||||
image_compression:
|
||||
$ref: '#/components/schemas/LibConfigImageCompression'
|
||||
redirects:
|
||||
$ref: '#/components/schemas/LibConfigRedirects'
|
||||
|
||||
LibConfigSource:
|
||||
properties:
|
||||
production_branch:
|
||||
type: string
|
||||
example: "librepages"
|
||||
staging_branch:
|
||||
type: string
|
||||
example: "librepages-staging"
|
||||
|
||||
LibConfigForms:
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
example: false
|
||||
|
||||
LibConfigImageCompression:
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
example: false
|
||||
|
||||
LibConfigRedirects:
|
||||
properties:
|
||||
from:
|
||||
type: string
|
||||
example: "/from"
|
||||
to:
|
||||
type: string
|
||||
example: "/to"
|
||||
|
||||
|
||||
eventsNewPayloadNewSite:
|
||||
properties:
|
||||
hostname:
|
||||
type: string
|
||||
example: "example.org"
|
||||
path:
|
||||
type: string
|
||||
example: "/tmp/example.org"
|
||||
branch:
|
||||
type: string
|
||||
example: "librepages"
|
||||
|
||||
eventsNewPayloadDeleteSite:
|
||||
properties:
|
||||
hostname:
|
||||
type: string
|
||||
example: "example.org"
|
||||
|
||||
securitySchemes:
|
||||
basicAuth:
|
||||
type: http
|
||||
scheme: basic
|
|
@ -1,20 +0,0 @@
|
|||
window.onload = function() {
|
||||
//<editor-fold desc="Changeable Configuration Block">
|
||||
|
||||
// the following lines will be replaced by docker/configurator, when it runs in a docker-container
|
||||
window.ui = SwaggerUIBundle({
|
||||
url: "/docs/openapi/openapi.yml",
|
||||
dom_id: '#swagger-ui',
|
||||
deepLinking: true,
|
||||
presets: [
|
||||
SwaggerUIBundle.presets.apis,
|
||||
SwaggerUIStandalonePreset
|
||||
],
|
||||
plugins: [
|
||||
SwaggerUIBundle.plugins.DownloadUrl
|
||||
],
|
||||
layout: "StandaloneLayout"
|
||||
});
|
||||
|
||||
//</editor-fold>
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
181
env/dummy_conductor/Cargo.lock
generated
vendored
181
env/dummy_conductor/Cargo.lock
generated
vendored
|
@ -2,59 +2,17 @@
|
|||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "addr2line"
|
||||
version = "0.22.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678"
|
||||
dependencies = [
|
||||
"gimli",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "adler"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.80"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
||||
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.72"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cc",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"miniz_oxide",
|
||||
"object",
|
||||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "dummy_conductor"
|
||||
version = "0.1.0"
|
||||
|
@ -63,22 +21,6 @@ dependencies = [
|
|||
"libconductor",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gimli"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -87,94 +29,33 @@ version = "1.0.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8af84674fe1f223a982c933a0ee1086ac4d4052aa0fb8060c12c6ad838e754"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.155"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
|
||||
|
||||
[[package]]
|
||||
name = "libconductor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"libconfig",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libconfig"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.batsense.net/librepages/libconfig#f54290c4bae26b51a4945e0bf812e2b99856963b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae"
|
||||
dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.14.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "object"
|
||||
version = "0.35.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pin-project-lite"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
version = "1.0.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-demangle"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.11"
|
||||
|
@ -183,29 +64,29 @@ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -223,40 +104,6 @@ dependencies = [
|
|||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.38.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"num_cpus",
|
||||
"pin-project-lite",
|
||||
"tokio-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-macros"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.66",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.4"
|
||||
|
|
3
env/dummy_conductor/Cargo.toml
vendored
3
env/dummy_conductor/Cargo.toml
vendored
|
@ -10,8 +10,5 @@ serde = { version = "1", features=["derive"]}
|
|||
serde_json = { version ="1", features = ["raw_value"]}
|
||||
async-trait = "0.1.57"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.23.0", features = ["rt-multi-thread", "macros", "rt"] }
|
||||
|
||||
[dependencies.libconductor]
|
||||
path = "../libconductor"
|
||||
|
|
4
env/dummy_conductor/src/lib.rs
vendored
4
env/dummy_conductor/src/lib.rs
vendored
|
@ -41,8 +41,8 @@ mod tests {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn all_good() {
|
||||
#[test]
|
||||
fn all_good() {
|
||||
let c = DummyConductor {};
|
||||
assert_eq!(c.name(), DUMMY_CONDUCTOR_NAME);
|
||||
assert!(c.health().await);
|
||||
|
|
37
env/libconductor/Cargo.lock
generated
vendored
37
env/libconductor/Cargo.lock
generated
vendored
|
@ -4,9 +4,9 @@ version = 3
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.80"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca"
|
||||
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -24,33 +24,24 @@ name = "libconductor"
|
|||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"libconfig",
|
||||
"serde",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libconfig"
|
||||
version = "0.1.0"
|
||||
source = "git+https://git.batsense.net/librepages/libconfig#f54290c4bae26b51a4945e0bf812e2b99856963b"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.85"
|
||||
version = "1.0.46"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
|
||||
checksum = "94e2ef8dbfc347b10c094890f778ee2e36ca9bb4262e86dc99cd217e35f3470b"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.36"
|
||||
version = "1.0.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
|
||||
checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
@ -63,18 +54,18 @@ checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09"
|
|||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.203"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
|
||||
checksum = "728eb6351430bccb993660dfffc5a72f91ccc1295abaa8ce19b27ebe4f75568b"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.203"
|
||||
version = "1.0.145"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
|
||||
checksum = "81fa1584d3d1bcacd84c277a0dfe21f5b0f6accf4a23d04d4c6d61f1af522b4c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -83,9 +74,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.117"
|
||||
version = "1.0.85"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
||||
checksum = "e55a28e3aaef9d5ce0506d0a14dbba8054ddc7e499ef522dd8b26859ec9d4a44"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
|
@ -94,9 +85,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.66"
|
||||
version = "1.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
|
||||
checksum = "e90cde112c4b9690b8cbe810cba9ddd8bc1d7472e2cae317b69e9438c1cba7d2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
|
1
env/libconductor/Cargo.toml
vendored
1
env/libconductor/Cargo.toml
vendored
|
@ -9,7 +9,6 @@ edition = "2021"
|
|||
serde = { version = "1", features=["derive"]}
|
||||
serde_json = { version ="1", features = ["raw_value"]}
|
||||
async-trait = { version = "0.1.57", optional = true}
|
||||
libconfig = { version = "0.1.0", git = "https://git.batsense.net/librepages/libconfig" }
|
||||
|
||||
[features]
|
||||
default = [
|
||||
|
|
14
env/libconductor/src/event_types.rs
vendored
14
env/libconductor/src/event_types.rs
vendored
|
@ -14,22 +14,10 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use libconfig::Config as LibConfig;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone)]
|
||||
#[serde(untagged)]
|
||||
pub enum EventType {
|
||||
NewSite {
|
||||
path: String,
|
||||
branch: String,
|
||||
hostname: String,
|
||||
},
|
||||
DeleteSite {
|
||||
hostname: String,
|
||||
},
|
||||
|
||||
Config {
|
||||
data: LibConfig,
|
||||
},
|
||||
NewHostname(String),
|
||||
}
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"config:recommended",
|
||||
":dependencyDashboard"
|
||||
],
|
||||
"labels": [
|
||||
"renovate-bot"
|
||||
],
|
||||
"prHourlyLimit": 0,
|
||||
"timezone": "Asia/kolkata",
|
||||
"prCreation": "immediate",
|
||||
"vulnerabilityAlerts": {
|
||||
"enabled": true,
|
||||
"labels": [
|
||||
"renovate-bot",
|
||||
"renovate-security",
|
||||
"security"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
#
|
||||
# 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
# publish.sh: grab bin from docker container, pack, sign and upload
|
||||
# $2: binary version
|
||||
# $3: Docker img tag
|
||||
# $4: dumbserve password
|
||||
|
||||
set -xEeuo pipefail
|
||||
|
||||
DUMBSERVE_USERNAME=librepages
|
||||
DUMBSERVE_PASSWORD=$4
|
||||
DUMBSERVE_HOST="https://$DUMBSERVE_USERNAME:$DUMBSERVE_PASSWORD@dl.librepages.org"
|
||||
|
||||
NAME=conductor
|
||||
KEY=67880CA5F4BC99BF247330E2DA576B07BC323961
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
FILENAME="$NAME-$2-linux-amd64"
|
||||
TARBALL=$FILENAME.tar.gz
|
||||
TARGET_DIR="$TMP_DIR/$FILENAME/"
|
||||
mkdir -p $TARGET_DIR
|
||||
DOCKER_IMG="realaravinth/$NAME:$3"
|
||||
|
||||
|
||||
get_bin(){
|
||||
cp target/release/conductor $TARGET_DIR
|
||||
cp -r config/ $TARGET_DIR
|
||||
cp -r contrib/ $TARGET_DIR
|
||||
}
|
||||
|
||||
copy() {
|
||||
echo "[*] Copying dist assets"
|
||||
cp README.md $TARGET_DIR
|
||||
cp LICENSE.md $TARGET_DIR
|
||||
|
||||
mkdir $TARGET_DIR/docs
|
||||
# cp docs/CONFIGURATION.md $TARGET_DIR/docs
|
||||
# cp -r docs/installation/ $TARGET_DIR/docs
|
||||
|
||||
get_bin
|
||||
}
|
||||
|
||||
pack() {
|
||||
echo "[*] Creating dist tarball"
|
||||
pushd $TMP_DIR
|
||||
tar -cvzf $TARBALL $FILENAME
|
||||
popd
|
||||
}
|
||||
|
||||
checksum() {
|
||||
echo "[*] Generating dist tarball checksum"
|
||||
pushd $TMP_DIR
|
||||
sha256sum $TARBALL > $TARBALL.sha256
|
||||
popd
|
||||
}
|
||||
|
||||
sign() {
|
||||
echo "[*] Signing dist tarball checksum"
|
||||
pushd $TMP_DIR
|
||||
export GPG_TTY=$(tty)
|
||||
gpg --verbose \
|
||||
--pinentry-mode loopback \
|
||||
--batch --yes \
|
||||
--passphrase $GPG_PASSWORD \
|
||||
--local-user $KEY \
|
||||
--output $TARBALL.asc \
|
||||
--sign --detach \
|
||||
--armor $TARBALL
|
||||
popd
|
||||
}
|
||||
|
||||
delete_dir() {
|
||||
curl --location --request DELETE "$DUMBSERVE_HOST/api/v1/files/delete" \
|
||||
--header 'Content-Type: application/json' \
|
||||
--data-raw "{
|
||||
\"path\": \"$1\"
|
||||
}"
|
||||
}
|
||||
|
||||
upload_dist() {
|
||||
upload_dist="conductor/$1"
|
||||
delete_dir $upload_dist
|
||||
|
||||
pushd $TMP_DIR
|
||||
for file in $TARBALL $TARBALL.asc $TARBALL.sha256
|
||||
do
|
||||
curl -v \
|
||||
-F upload=@$file \
|
||||
"$DUMBSERVE_HOST/api/v1/files/upload?path=$upload_dist/"
|
||||
done
|
||||
popd
|
||||
}
|
||||
|
||||
|
||||
publish() {
|
||||
copy
|
||||
pack
|
||||
checksum
|
||||
sign
|
||||
upload_dist $2
|
||||
}
|
||||
|
||||
$1 $@
|
|
@ -14,32 +14,11 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use actix_web::dev::ServiceRequest;
|
||||
use actix_web::web;
|
||||
use actix_web::Error;
|
||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||
|
||||
use crate::errors::*;
|
||||
use crate::AppCtx;
|
||||
use crate::SETTINGS;
|
||||
|
||||
pub mod meta;
|
||||
pub mod webhook;
|
||||
|
||||
pub async fn bearerauth(
|
||||
req: ServiceRequest,
|
||||
credentials: BearerAuth,
|
||||
) -> Result<ServiceRequest, (Error, ServiceRequest)> {
|
||||
let _ctx: &AppCtx = req.app_data().unwrap();
|
||||
let token = credentials.token();
|
||||
if SETTINGS.authenticate(token) {
|
||||
Ok(req)
|
||||
} else {
|
||||
let e = Error::from(ServiceError::Unauthorized);
|
||||
Err((e, req))
|
||||
}
|
||||
}
|
||||
|
||||
pub const API_V1_ROUTES: routes::Routes = routes::Routes::new();
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use actix_web::{web, HttpResponse, Responder};
|
||||
use actix_web_httpauth::middleware::HttpAuthentication;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use libconductor::EventType;
|
||||
|
@ -24,8 +23,6 @@ use crate::errors::*;
|
|||
use crate::AppCtx;
|
||||
use crate::*;
|
||||
|
||||
use super::bearerauth;
|
||||
|
||||
pub mod routes {
|
||||
use super::*;
|
||||
#[derive(Debug, Eq, PartialEq, Deserialize, Serialize)]
|
||||
|
@ -45,10 +42,7 @@ pub fn services(cfg: &mut web::ServiceConfig) {
|
|||
cfg.service(post_event);
|
||||
}
|
||||
|
||||
#[actix_web_codegen_const_routes::post(
|
||||
path = "API_V1_ROUTES.webhook.post_event",
|
||||
wrap = "HttpAuthentication::bearer(bearerauth)"
|
||||
)]
|
||||
#[actix_web_codegen_const_routes::post(path = "API_V1_ROUTES.webhook.post_event")]
|
||||
async fn post_event(ctx: AppCtx, payload: web::Json<EventType>) -> ServiceResult<impl Responder> {
|
||||
ctx.conductor.process(payload.into_inner()).await;
|
||||
Ok(HttpResponse::Created())
|
||||
|
@ -56,9 +50,10 @@ async fn post_event(ctx: AppCtx, payload: web::Json<EventType>) -> ServiceResult
|
|||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use actix_web::{http::StatusCode, test, App};
|
||||
|
||||
use super::*;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn submit_works() {
|
||||
let settings = Settings::new().unwrap();
|
||||
|
@ -70,22 +65,14 @@ pub mod tests {
|
|||
)
|
||||
.await;
|
||||
|
||||
let creds = settings.creds.clone();
|
||||
let auth = format!("Bearer {}", creds.token,);
|
||||
|
||||
let msg = EventType::NewSite {
|
||||
hostname: "demo.librepages.org".into(),
|
||||
branch: "librepages".into(),
|
||||
path: "/tmp/librepages".into(),
|
||||
};
|
||||
let new_hostname = EventType::NewHostname("demo.librepages.org".into());
|
||||
|
||||
// upload json
|
||||
let upload_json = test::call_service(
|
||||
&app,
|
||||
test::TestRequest::post()
|
||||
.append_header((actix_web::http::header::AUTHORIZATION, auth.clone()))
|
||||
.uri(API_V1_ROUTES.webhook.post_event)
|
||||
.set_json(&msg)
|
||||
.set_json(&new_hostname)
|
||||
.to_request(),
|
||||
)
|
||||
.await;
|
||||
|
|
10
src/ctx.rs
10
src/ctx.rs
|
@ -37,9 +37,13 @@ impl Ctx {
|
|||
pub async fn new(s: &Settings) -> ArcCtx {
|
||||
let source_code = {
|
||||
let mut url = s.source_code.clone();
|
||||
url = url.join("tree/").unwrap();
|
||||
url = url.join(crate::GIT_COMMIT_HASH).unwrap();
|
||||
url.into()
|
||||
if !url.ends_with('/') {
|
||||
url.push('/');
|
||||
}
|
||||
let mut base = url::Url::parse(&url).unwrap();
|
||||
base = base.join("tree/").unwrap();
|
||||
base = base.join(crate::GIT_COMMIT_HASH).unwrap();
|
||||
base.into()
|
||||
};
|
||||
|
||||
let conductor: Box<dyn Conductor> = match s.conductor {
|
||||
|
|
128
src/docs.rs
128
src/docs.rs
|
@ -1,128 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2022 Aravinth Manivannan <realaravinth@batsense.net>
|
||||
*
|
||||
* 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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
use std::borrow::Cow;
|
||||
|
||||
use actix_web::body::BoxBody;
|
||||
use actix_web::{http::header, web, HttpResponse, Responder};
|
||||
use mime_guess::from_path;
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
use crate::CACHE_AGE;
|
||||
|
||||
pub const DOCS: routes::Docs = routes::Docs::new();
|
||||
|
||||
pub mod routes {
|
||||
pub struct Docs {
|
||||
pub home: &'static str,
|
||||
pub spec: &'static str,
|
||||
pub assets: &'static str,
|
||||
}
|
||||
|
||||
impl Docs {
|
||||
pub const fn new() -> Self {
|
||||
Docs {
|
||||
home: "/docs/openapi",
|
||||
spec: "/docs/openapi/openapi.yml",
|
||||
assets: "/docs/openapi/{_:.*}",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||
cfg.service(index).service(spec).service(dist);
|
||||
}
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "docs/openapi/"]
|
||||
struct Asset;
|
||||
|
||||
pub fn handle_embedded_file(path: &str) -> HttpResponse {
|
||||
match Asset::get(path) {
|
||||
Some(content) => {
|
||||
let body: BoxBody = match content.data {
|
||||
Cow::Borrowed(bytes) => BoxBody::new(bytes),
|
||||
Cow::Owned(bytes) => BoxBody::new(bytes),
|
||||
};
|
||||
|
||||
HttpResponse::Ok()
|
||||
.insert_header(header::CacheControl(vec![
|
||||
header::CacheDirective::Public,
|
||||
header::CacheDirective::Extension("immutable".into(), None),
|
||||
header::CacheDirective::MaxAge(CACHE_AGE),
|
||||
]))
|
||||
.content_type(from_path(path).first_or_octet_stream().as_ref())
|
||||
.body(body)
|
||||
}
|
||||
None => HttpResponse::NotFound().body("404 Not Found"),
|
||||
}
|
||||
}
|
||||
|
||||
#[actix_web_codegen_const_routes::get(path = "DOCS.assets")]
|
||||
async fn dist(path: web::Path<String>) -> impl Responder {
|
||||
handle_embedded_file(&path)
|
||||
}
|
||||
const OPEN_API_SPEC: &str = include_str!("../docs/openapi/openapi.yml");
|
||||
|
||||
#[actix_web_codegen_const_routes::get(path = "DOCS.spec")]
|
||||
async fn spec() -> HttpResponse {
|
||||
HttpResponse::Ok()
|
||||
.content_type("text/yaml")
|
||||
.body(OPEN_API_SPEC)
|
||||
}
|
||||
|
||||
#[actix_web_codegen_const_routes::get(path = "DOCS.home")]
|
||||
async fn index() -> HttpResponse {
|
||||
handle_embedded_file("index.html")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use actix_web::http::StatusCode;
|
||||
use actix_web::test;
|
||||
|
||||
use super::*;
|
||||
use crate::*;
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn docs_works() {
|
||||
const FILE: &str = "openapi.yml";
|
||||
|
||||
let app = test::init_service(
|
||||
App::new()
|
||||
.wrap(actix_web::middleware::NormalizePath::new(
|
||||
actix_web::middleware::TrailingSlash::Trim,
|
||||
))
|
||||
.configure(services),
|
||||
)
|
||||
.await;
|
||||
|
||||
let resp =
|
||||
test::call_service(&app, test::TestRequest::get().uri(DOCS.home).to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
let resp =
|
||||
test::call_service(&app, test::TestRequest::get().uri(DOCS.spec).to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
|
||||
let uri = format!("{}/{}", DOCS.home, "favicon-32x32.png");
|
||||
println!("{uri}");
|
||||
|
||||
let resp = test::call_service(&app, test::TestRequest::get().uri(&uri).to_request()).await;
|
||||
assert_eq!(resp.status(), StatusCode::OK);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,6 @@ use std::env;
|
|||
use actix_web::http::StatusCode;
|
||||
use actix_web::web::JsonConfig;
|
||||
use actix_web::{error::InternalError, middleware, App, HttpServer};
|
||||
use actix_web_prom::PrometheusMetricsBuilder;
|
||||
use clap::{Parser, Subcommand};
|
||||
use log::info;
|
||||
|
||||
|
@ -27,7 +26,7 @@ use lazy_static::lazy_static;
|
|||
|
||||
mod api;
|
||||
mod ctx;
|
||||
mod docs;
|
||||
//mod docs;
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
mod errors;
|
||||
//#[macro_use]
|
||||
|
@ -113,11 +112,6 @@ async fn serve(settings: Settings, ctx: AppCtx) -> std::io::Result<()> {
|
|||
let ip = settings.server.get_ip();
|
||||
println!("Starting server on: http://{ip}");
|
||||
|
||||
let prometheus = PrometheusMetricsBuilder::new("api")
|
||||
.endpoint("/metrics")
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
HttpServer::new(move || {
|
||||
App::new()
|
||||
.wrap(middleware::Logger::default())
|
||||
|
@ -130,7 +124,6 @@ async fn serve(settings: Settings, ctx: AppCtx) -> std::io::Result<()> {
|
|||
middleware::TrailingSlash::Trim,
|
||||
))
|
||||
.app_data(get_json_err())
|
||||
.wrap(prometheus.clone())
|
||||
.configure(routes::services)
|
||||
})
|
||||
.bind(ip)?
|
||||
|
|
|
@ -17,6 +17,5 @@
|
|||
use actix_web::web;
|
||||
|
||||
pub fn services(cfg: &mut web::ServiceConfig) {
|
||||
crate::docs::services(cfg);
|
||||
crate::api::v1::services(cfg);
|
||||
}
|
||||
|
|
101
src/settings.rs
101
src/settings.rs
|
@ -17,17 +17,13 @@
|
|||
use std::env;
|
||||
use std::path::Path;
|
||||
|
||||
use config::{builder::DefaultState, Config, ConfigBuilder, ConfigError, Environment, File};
|
||||
use config::{Config, ConfigError, Environment, File};
|
||||
use derive_more::Display;
|
||||
use log::info;
|
||||
use log::warn;
|
||||
use serde::Deserialize;
|
||||
use serde::Serialize;
|
||||
use url::Url;
|
||||
|
||||
const PREFIX: &str = "LPCONDUCTOR";
|
||||
const SEPARATOR: &str = "_";
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Server {
|
||||
pub port: u32,
|
||||
|
@ -52,115 +48,58 @@ pub enum ConductorType {
|
|||
Dummy,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Creds {
|
||||
pub token: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct Settings {
|
||||
pub debug: bool,
|
||||
pub creds: Creds,
|
||||
pub server: Server,
|
||||
pub source_code: Url,
|
||||
pub source_code: String,
|
||||
pub conductor: ConductorType,
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
impl Settings {
|
||||
pub fn authenticate(&self, token: &str) -> bool {
|
||||
self.creds.token == token
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self, ConfigError> {
|
||||
let mut s = Config::builder();
|
||||
let mut s = Config::new();
|
||||
|
||||
const CURRENT_DIR: &str = "./config/config.toml";
|
||||
const ETC: &str = "/etc/librepages/conductor/config.toml";
|
||||
const CURRENT_DIR: &str = "./config/default.toml";
|
||||
const ETC: &str = "/etc/lpconductor/config.toml";
|
||||
|
||||
if let Ok(path) = env::var("LPCONDUCTOR_CONFIG") {
|
||||
s = s.add_source(File::with_name(&path));
|
||||
s.merge(File::with_name(&path))?;
|
||||
} else if Path::new(CURRENT_DIR).exists() {
|
||||
// merging default config from file
|
||||
s = s.add_source(File::with_name(CURRENT_DIR));
|
||||
s.merge(File::with_name(CURRENT_DIR))?;
|
||||
} else if Path::new(ETC).exists() {
|
||||
s = s.add_source(File::with_name(ETC));
|
||||
s.merge(File::with_name(ETC))?;
|
||||
} else {
|
||||
warn!("configuration file not found");
|
||||
log::warn!("configuration file not found");
|
||||
}
|
||||
|
||||
s = s.add_source(Environment::with_prefix(PREFIX).separator(SEPARATOR));
|
||||
s = set_separator_field(s);
|
||||
s.merge(Environment::with_prefix("LPCONDUCTOR").separator("_"))?;
|
||||
|
||||
check_url(&s);
|
||||
|
||||
match env::var("PORT") {
|
||||
Ok(val) => {
|
||||
s = s.set_override("server.port", val).unwrap();
|
||||
s.set("server.port", val).unwrap();
|
||||
}
|
||||
Err(e) => warn!("couldn't interpret PORT: {}", e),
|
||||
}
|
||||
|
||||
let s = s.build()?;
|
||||
match s.try_deserialize::<Self>() {
|
||||
match s.try_into::<Self>() {
|
||||
Ok(val) => {
|
||||
Ok(val)
|
||||
},
|
||||
Err(e) => Err(ConfigError::Message(format!("\n\nError: {}. If it says missing fields, then please refer to https://git.batsense.net/LibrePages/conductor to learn more about how conductor reads configuration\n\n", e))),
|
||||
Err(e) => Err(ConfigError::Message(format!("\n\nError: {}. If it says missing fields, then please refer to https://github.com/mCaptcha/mcaptcha#configuration to learn more about how mcaptcha reads configuration\n\n", e))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(tarpaulin_include))]
|
||||
fn set_separator_field(mut s: ConfigBuilder<DefaultState>) -> ConfigBuilder<DefaultState> {
|
||||
// ref: https://github.com/mehcode/config-rs/issues/391
|
||||
fn check_url(s: &Config) {
|
||||
let url = s
|
||||
.get::<String>("source_code")
|
||||
.expect("Couldn't access source_code");
|
||||
|
||||
fn from_env(
|
||||
s: ConfigBuilder<DefaultState>,
|
||||
env_name: &str,
|
||||
config_name: &str,
|
||||
) -> ConfigBuilder<DefaultState> {
|
||||
if let Ok(val) = env::var(env_name) {
|
||||
info!("Overriding {config_name} with data from env var {env_name}");
|
||||
s.set_override(config_name, val)
|
||||
.unwrap_or_else(|_| panic!("Couldn't set {config_name} from env var {env_name}"))
|
||||
} else {
|
||||
s
|
||||
}
|
||||
}
|
||||
s = from_env(s, &format!("{PREFIX}{SEPARATOR}SOURCE_CODE"), "source_code");
|
||||
s = from_env(
|
||||
s,
|
||||
&format!("{PREFIX}{SEPARATOR}SERVER{SEPARATOR}URL_PREFIX"),
|
||||
"server.url_prefix",
|
||||
);
|
||||
s = from_env(
|
||||
s,
|
||||
&format!("{PREFIX}{SEPARATOR}SERVER{SEPARATOR}PROXY_HAS_TLS"),
|
||||
"server.proxy_has_tls",
|
||||
);
|
||||
|
||||
s = from_env(
|
||||
s,
|
||||
&format!("{PREFIX}{SEPARATOR}CREDS{SEPARATOR}TOKEN"),
|
||||
"creds.token",
|
||||
);
|
||||
|
||||
s
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn creds_works() {
|
||||
let settings = Settings::new().unwrap();
|
||||
let creds = settings.creds.clone();
|
||||
|
||||
assert!(settings.authenticate(&creds.token));
|
||||
|
||||
let mut creds = settings.creds.clone();
|
||||
|
||||
creds.token = "noexist".into();
|
||||
assert!(!settings.authenticate(&creds.token))
|
||||
}
|
||||
Url::parse(&url).expect("Please enter a URL for source_code in settings");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue