1
0
Fork 0

scanservjs: Deploy scanserv-js

*scanserv-js* is a web-based front-end for SANE.  It allows scanning
documents from a browser.

Using the `config.local.js` file, we implement the `afterScan` hook to
automatically upload scanned files to *paperless-ngx* using its REST
API.
dch-webhooks-secrets
Dustin 2023-04-19 21:29:14 -05:00
parent 8a966a7ffb
commit 1c31c01688
7 changed files with 300 additions and 0 deletions

1
scanservjs/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
paperless.token

36
scanservjs/README.md Normal file
View File

@ -0,0 +1,36 @@
# scanserv-js
[scanservjs][0] is an open source, web-based front-end for the [SANE][1]
software suite. It provides a simple graphical user interface for scanning
photos and documents using any local or network-connected SANE-compatible
scanner.
## Installation
```sh
kubectl apply -k scanservjs
```
Environment variables used by the [container image][2] can be set in the
`scanservjs.env` file.
## Integration with *paperless-ngx*
[paperless-ngx][3] is an open-source, web-based document management platform.
Integrating *scanservjs* with *paperless-ngx* allows scanned documents to be
fed automatically into the document management system for OCR, analysis, and
classification. This integration is performed using the `afterScan` hook in
the *scanservjs* `config.local.js` file and the *paperless-ngx* REST API to
upload documents scanned as PDF files.
To enable the integration, specify the URL to the *paperless-ngx* service in
the `PAPERLESS_URL` environment variable. Additionally, create an
[authentication token][4] for *paperless-ngx* user, store it in a file, and set
the `PAPERLESS_TOKEN_FILE` environment variable to the file path.
[0]: https://github.com/sbs20/scanservjs
[1]: http://sane-project.org/
[2]: https://github.com/sbs20/scanservjs/blob/master/docs/docker.md
[3]: https://docs.paperless-ngx.com/
[4]: https://docs.paperless-ngx.com/api/#authorization

View File

@ -0,0 +1,77 @@
// vim: set sw=2 ts=2 sts=2 et :
const fs = require('node:fs/promises');
const http = require('node:http');
const https = require('node:https');
const path = require('node:path');
const HANDLERS = {
'http': http,
'https': https,
}
async function get_token() {
const buf = await fs.readFile(
process.env['PAPERLESS_TOKEN_FILE'],
'utf-8',
);
return buf.trimEnd();
}
async function paperless_send(filepath) {
if (!'PAPERLESS_URL' in process.env) {
return
}
const filename = path.basename(filepath);
const boundary = `------------------------${Math.random() * 1e16}`;
const token = await get_token();
const options = {
method: 'POST',
headers: {
'Content-Type': `multipart/form-data; boundary=${boundary}`,
'Authorization': `Token ${token}`,
},
};
const url = new URL(
process.env['PAPERLESS_URL'] + '/api/documents/post_document/'
);
console.log('Uploading', filename, 'to', url.toString());
const handler = HANDLERS[url.protocol.slice(0, -1)];
const req = handler.request(url, options, (res) => {
console.log('Received HTTP status code', res.statusCode, 'from Paperless');
});
req.on('error', (e) => {
console.error(e);
});
const header = `--${boundary}\r\n` +
`Content-Disposition: form-data; name="document"; filename="${filename}"\r\n` +
`\r\n`
const trailer = `\r\n--${boundary}--\r\n`
const f = await fs.open(filepath);
const st = await f.stat();
const length = header.length + st.size + trailer.length;
req.setHeader('Content-Length', length.toString());
req.write(header)
while (1) {
const d = await f.read();
if (!d.bytesRead) {
break;
}
req.write(d.buffer.slice(0, d.bytesRead));
};
await f.close();
req.write(trailer);
req.end();
console.log('Upload complete');
}
module.exports = {
async afterScan(fileInfo) {
if (fileInfo.name.endsWith('.pdf')) {
await paperless_send(fileInfo.fullname);
}
}
}

36
scanservjs/ingress.yaml Normal file
View File

@ -0,0 +1,36 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
labels:
app.kubernetes.io/name: scanservjs
app.kubernetes.io/component: scanservjs
app.kubernetes.io/instance: scanservjs
app.kubernetes.io/part-of: scanservjs
annotations:
nginx.ingress.kubernetes.io/proxy-body-size: '0'
nginx.ingress.kubernetes.io/auth-method: GET
nginx.ingress.kubernetes.io/auth-url: http://authelia.authelia.svc.cluster.local:9091/api/verify
nginx.ingress.kubernetes.io/auth-signin: https://auth.pyrocufflink.blue/?rm=$request_method
nginx.ingress.kubernetes.io/auth-response-headers: Remote-User,Remote-Name,Remote-Groups,Remote-Email
nginx.ingress.kubernetes.io/auth-snippet: |
proxy_set_header X-Forwarded-Method $request_method;
name: scanservjs
namespace: scanservjs
spec:
ingressClassName: nginx
tls:
- hosts:
- scan.pyrocufflink.blue
rules:
- host: scan.pyrocufflink.blue
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: scanservjs
port:
name: http

View File

@ -0,0 +1,29 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- scanservjs.yaml
- ingress.yaml
configMapGenerator:
- name: scanservjs
namespace: scanservjs
envs:
- scanservjs.env
options:
disableNameSuffixHash: true
- name: scanservjs-config
namespace: scanservjs
files:
- config.local.js
options:
disableNameSuffixHash: true
secretGenerator:
- name: paperless-token
namespace: scanservjs
files:
- paperless.token
options:
disableNameSuffixHash: true

View File

@ -0,0 +1,3 @@
SCANIMAGE_LIST_IGNORE=true
DEVICES=escl:https://172.30.0.234:443
PAPERLESS_URL=http://paperless-ngx.paperless-ngx.svc.cluster.local:8000

118
scanservjs/scanservjs.yaml Normal file
View File

@ -0,0 +1,118 @@
apiVersion: v1
kind: Namespace
metadata:
name: scanservjs
---
apiVersion: v1
kind: Service
metadata:
labels:
app.kubernetes.io/name: scanservjs
app.kubernetes.io/component: scanservjs
app.kubernetes.io/instance: scanservjs
app.kubernetes.io/part-of: scanservjs
name: scanservjs
namespace: scanservjs
spec:
ports:
- name: http
port: 8080
selector:
app.kubernetes.io/name: scanservjs
app.kubernetes.io/component: scanservjs
app.kubernetes.io/instance: scanservjs
type: ClusterIP
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: scanservjs
namespace: scanservjs
labels:
app.kubernetes.io/name: scanservjs
app.kubernetes.io/component: scanservjs
app.kubernetes.io/instance: scanservjs
app.kubernetes.io/part-of: scanservjs
spec:
selector:
matchLabels:
app.kubernetes.io/name: scanservjs
app.kubernetes.io/component: scanservjs
app.kubernetes.io/instance: scanservjs
template:
metadata:
labels:
app.kubernetes.io/name: scanservjs
app.kubernetes.io/component: scanservjs
app.kubernetes.io/instance: scanservjs
spec:
initContainers:
- name: init-data
image: docker.io/sbs20/scanservjs:v2.26.1
imagePullPolicy: IfNotPresent
command:
- cp
- -r
- /app/data/.
- /tmp/data
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
runAsUser: 1000
runAsGroup: 1000
volumeMounts:
- name: scanservjs-datadir
mountPath: /tmp/data
containers:
- name: scanservjs
image: docker.io/sbs20/scanservjs:v2.26.1
imagePullPolicy: IfNotPresent
env:
- name: PAPERLESS_TOKEN_FILE
value: /run/secrets/paperless.token
envFrom:
- configMapRef:
name: scanservjs
optional: true
ports:
- name: scanservjs
containerPort: 8080
securityContext:
runAsNonRoot: true
readOnlyRootFilesystem: true
runAsUser: 1000
runAsGroup: 1000
volumeMounts:
- name: scanservjs-datadir
mountPath: /app/data
- name: scanservjs-configdir
mountPath: /app/config
- name: scanservjs-config
mountPath: /app/config/config.local.js
subPath: config.local.js
- name: scanservjs-tmp
mountPath: /tmp
- name: paperless-token
mountPath: /run/secrets/paperless.token
subPath: paperless.token
readOnly: true
securityContext:
fsGroup: 1000
volumes:
- name: scanservjs-datadir
emptyDir:
- name: scanservjs-configdir
emptyDir:
medium: Memory
- name: scanservjs-tmp
emptyDir:
medium: Memory
- name: scanservjs-config
configMap:
name: scanservjs-config
- name: paperless-token
secret:
secretName: paperless-token
optional: true