Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3c74cc14df | ||
|
|
a165f8ec4d | ||
|
|
d6a88f2a22 | ||
|
|
b8172efd59 | ||
|
|
cbe37c6798 | ||
|
|
a545c44426 | ||
|
|
08a2f60f72 | ||
|
|
907e56af0f | ||
|
|
888a0c5faf | ||
|
|
bfb0d151ea | ||
|
|
1f63f22591 | ||
|
|
a2d5e0f72c | ||
|
|
c0d0f6fa90 | ||
|
|
4a016ed57d | ||
|
|
5ea63fb60b | ||
|
|
57cb683c64 |
25
CHANGELOG.md
25
CHANGELOG.md
@@ -1,3 +1,28 @@
|
||||
### [0.3.3](https://github.com/stonith404/pingvin-share/compare/v0.3.2...v0.3.3) (2022-12-08)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add support for different email and user ([888a0c5](https://github.com/stonith404/pingvin-share/commit/888a0c5fafc51b6872ed71e37d4b40c9bf6a07f1))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* allow empty strings in config variable ([b8172ef](https://github.com/stonith404/pingvin-share/commit/b8172efd59fb3271ab9b818b13a7003342b2cebd))
|
||||
* improve admin dashboard color and layout ([a545c44](https://github.com/stonith404/pingvin-share/commit/a545c444261c90105dcb165ebcf4b26634e729ca))
|
||||
* obscure critical config variables ([bfb0d15](https://github.com/stonith404/pingvin-share/commit/bfb0d151ea2ba125e536a16b1873e143a67e9f64))
|
||||
* obscured text length ([cbe37c6](https://github.com/stonith404/pingvin-share/commit/cbe37c679853ecef1522ed213e4cac5defd5b45a))
|
||||
* space character in email ([907e56a](https://github.com/stonith404/pingvin-share/commit/907e56af0faccdbc8d7f5ab3418a4ad71ff849f5))
|
||||
|
||||
### [0.3.2](https://github.com/stonith404/pingvin-share/compare/v0.3.1...v0.3.2) (2022-12-07)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* make share password optional ([57cb683](https://github.com/stonith404/pingvin-share/commit/57cb683c64eaedec2697ea6863948bd2ae68dd75))
|
||||
* unauthenticated dialog not shown ([4a016ed](https://github.com/stonith404/pingvin-share/commit/4a016ed57db526ee900c567f7b7f0991f948c631))
|
||||
* use session storage for share token ([5ea63fb](https://github.com/stonith404/pingvin-share/commit/5ea63fb60be0c508c38ba228cc8ac6dd7b403aac))
|
||||
|
||||
### [0.3.1](https://github.com/stonith404/pingvin-share/compare/v0.3.0...v0.3.1) (2022-12-05)
|
||||
|
||||
|
||||
|
||||
12
Dockerfile
12
Dockerfile
@@ -1,11 +1,12 @@
|
||||
FROM node:18-alpine AS frontend-builder
|
||||
FROM node:18-slim AS frontend-builder
|
||||
WORKDIR /opt/app
|
||||
COPY frontend/package.json frontend/package-lock.json ./
|
||||
RUN npm ci
|
||||
COPY ./frontend .
|
||||
RUN npm run build
|
||||
|
||||
FROM node:18 AS backend-builder
|
||||
FROM node:18-slim AS backend-builder
|
||||
RUN apt-get update && apt-get install -y openssl
|
||||
WORKDIR /opt/app
|
||||
COPY backend/package.json backend/package-lock.json ./
|
||||
RUN npm ci
|
||||
@@ -13,9 +14,10 @@ COPY ./backend .
|
||||
RUN npx prisma generate
|
||||
RUN npm run build
|
||||
|
||||
FROM node:18 AS runner
|
||||
WORKDIR /opt/app/frontend
|
||||
FROM node:18-slim AS runner
|
||||
ENV NODE_ENV=production
|
||||
RUN apt-get update && apt-get install -y openssl
|
||||
WORKDIR /opt/app/frontend
|
||||
COPY --from=frontend-builder /opt/app/next.config.js .
|
||||
COPY --from=frontend-builder /opt/app/public ./public
|
||||
COPY --from=frontend-builder /opt/app/.next ./.next
|
||||
@@ -26,7 +28,7 @@ COPY --from=backend-builder /opt/app/node_modules ./node_modules
|
||||
COPY --from=backend-builder /opt/app/dist ./dist
|
||||
COPY --from=backend-builder /opt/app/prisma ./prisma
|
||||
COPY --from=backend-builder /opt/app/package.json ./
|
||||
WORKDIR /opt/app
|
||||
|
||||
WORKDIR /opt/app
|
||||
EXPOSE 3000
|
||||
CMD cd frontend && node_modules/.bin/next start & cd backend && npm run prod
|
||||
13
README.md
13
README.md
@@ -2,12 +2,6 @@
|
||||
|
||||
Pingvin Share is self-hosted file sharing platform and an alternative for WeTransfer.
|
||||
|
||||
## 🎪 Showcase
|
||||
|
||||
Demo: https://pingvin-share.dev.eliasschneider.com
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/58886915/167101708-b85032ad-f5b1-480a-b8d7-ec0096ea2a43.png" width="700"/>
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- Spin up your instance within 2 minutes
|
||||
@@ -18,6 +12,13 @@ Demo: https://pingvin-share.dev.eliasschneider.com
|
||||
- Email recepients
|
||||
- Light & dark mode
|
||||
|
||||
## 🐧 Get to know Pingvin Share
|
||||
|
||||
- [Demo](https://pingvin-share.dev.eliasschneider.com)
|
||||
- [Review by DB Tech](https://www.youtube.com/watch?v=rWwNeZCOPJA)
|
||||
|
||||
<img src="https://user-images.githubusercontent.com/58886915/167101708-b85032ad-f5b1-480a-b8d7-ec0096ea2a43.png" width="700"/>
|
||||
|
||||
## ⌨️ Setup
|
||||
|
||||
> Pleas note that Pingvin Share is in early stage and could include some bugs
|
||||
|
||||
177
backend/package-lock.json
generated
177
backend/package-lock.json
generated
@@ -60,7 +60,8 @@
|
||||
"ts-loader": "^9.4.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "4.1.1",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"wait-on": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@angular-devkit/core": {
|
||||
@@ -390,6 +391,21 @@
|
||||
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@hapi/hoek": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
|
||||
"integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@hapi/topo": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
|
||||
"integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@humanwhocodes/config-array": {
|
||||
"version": "0.11.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
|
||||
@@ -1027,6 +1043,27 @@
|
||||
"integrity": "sha512-Bd4LZ+WAnUHOq31e9X/ihi5zPlr4SzTRwUZZYxvWOxlerIZ7HJlVa9zXpuKTKLpI9O1l8Ec4OYCKsivWCs5a3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sideway/address": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||
"integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@sideway/formula": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
|
||||
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@sideway/pinpoint": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
|
||||
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@tsconfig/node10": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||
@@ -1983,6 +2020,15 @@
|
||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
|
||||
"integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.7"
|
||||
}
|
||||
},
|
||||
"node_modules/balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -3518,6 +3564,26 @@
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
@@ -4264,6 +4330,19 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/joi": {
|
||||
"version": "17.7.0",
|
||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz",
|
||||
"integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@hapi/hoek": "^9.0.0",
|
||||
"@hapi/topo": "^5.0.0",
|
||||
"@sideway/address": "^4.1.3",
|
||||
"@sideway/formula": "^3.0.0",
|
||||
"@sideway/pinpoint": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-sdsl": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
|
||||
@@ -7134,6 +7213,25 @@
|
||||
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/wait-on": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz",
|
||||
"integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"axios": "^0.25.0",
|
||||
"joi": "^17.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"minimist": "^1.2.5",
|
||||
"rxjs": "^7.5.4"
|
||||
},
|
||||
"bin": {
|
||||
"wait-on": "bin/wait-on"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
@@ -7704,6 +7802,21 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"@hapi/hoek": {
|
||||
"version": "9.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz",
|
||||
"integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@hapi/topo": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz",
|
||||
"integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"@humanwhocodes/config-array": {
|
||||
"version": "0.11.7",
|
||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.7.tgz",
|
||||
@@ -8138,6 +8251,27 @@
|
||||
"integrity": "sha512-Bd4LZ+WAnUHOq31e9X/ihi5zPlr4SzTRwUZZYxvWOxlerIZ7HJlVa9zXpuKTKLpI9O1l8Ec4OYCKsivWCs5a3Q==",
|
||||
"dev": true
|
||||
},
|
||||
"@sideway/address": {
|
||||
"version": "4.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz",
|
||||
"integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/hoek": "^9.0.0"
|
||||
}
|
||||
},
|
||||
"@sideway/formula": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
|
||||
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
|
||||
"dev": true
|
||||
},
|
||||
"@sideway/pinpoint": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz",
|
||||
"integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@tsconfig/node10": {
|
||||
"version": "1.0.9",
|
||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz",
|
||||
@@ -8925,6 +9059,15 @@
|
||||
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==",
|
||||
"dev": true
|
||||
},
|
||||
"axios": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.25.0.tgz",
|
||||
"integrity": "sha512-cD8FOb0tRH3uuEe6+evtAbgJtfxr7ly3fQjYcMcuPlgkwVS9xboaVIpcDV+cYQe+yGykgwZCs1pzjntcGa6l5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"follow-redirects": "^1.14.7"
|
||||
}
|
||||
},
|
||||
"balanced-match": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
|
||||
@@ -10090,6 +10233,12 @@
|
||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
|
||||
"dev": true
|
||||
},
|
||||
"forever-agent": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
|
||||
@@ -10637,6 +10786,19 @@
|
||||
"resolved": "https://registry.npmjs.org/iterare/-/iterare-1.2.1.tgz",
|
||||
"integrity": "sha512-RKYVTCjAnRthyJes037NX/IiqeidgN1xc3j1RjFfECFp28A1GVwK9nA+i0rJPaHqSZwygLzRnFlzUuHFoWWy+Q=="
|
||||
},
|
||||
"joi": {
|
||||
"version": "17.7.0",
|
||||
"resolved": "https://registry.npmjs.org/joi/-/joi-17.7.0.tgz",
|
||||
"integrity": "sha512-1/ugc8djfn93rTE3WRKdCzGGt/EtiYKxITMO4Wiv6q5JL1gl9ePt4kBsl1S499nbosspfctIQTpYIhSmHA3WAg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@hapi/hoek": "^9.0.0",
|
||||
"@hapi/topo": "^5.0.0",
|
||||
"@sideway/address": "^4.1.3",
|
||||
"@sideway/formula": "^3.0.0",
|
||||
"@sideway/pinpoint": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"js-sdsl": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.1.5.tgz",
|
||||
@@ -12786,6 +12948,19 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"wait-on": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wait-on/-/wait-on-6.0.1.tgz",
|
||||
"integrity": "sha512-zht+KASY3usTY5u2LgaNqn/Cd8MukxLGjdcZxT2ns5QzDmTFc4XoWBgC+C/na+sMRZTuVygQoMYwdcVjHnYIVw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"axios": "^0.25.0",
|
||||
"joi": "^17.6.0",
|
||||
"lodash": "^4.17.21",
|
||||
"minimist": "^1.2.5",
|
||||
"rxjs": "^7.5.4"
|
||||
}
|
||||
},
|
||||
"watchpack": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz",
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"prod": "prisma migrate deploy && prisma db seed && node dist/src/main",
|
||||
"lint": "eslint 'src/**/*.ts'",
|
||||
"format": "prettier --write 'src/**/*.ts'",
|
||||
"test:system": "prisma migrate reset -f && nest start & sleep 10 && newman run ./test/system/newman-system-tests.json"
|
||||
"test:system": "prisma migrate reset -f && nest start & wait-on http://localhost:8080/api/configs && newman run ./test/system/newman-system-tests.json"
|
||||
},
|
||||
"prisma": {
|
||||
"seed": "ts-node prisma/seed/config.seed.ts"
|
||||
@@ -65,6 +65,7 @@
|
||||
"ts-loader": "^9.4.2",
|
||||
"ts-node": "^10.9.1",
|
||||
"tsconfig-paths": "4.1.1",
|
||||
"typescript": "^4.9.3"
|
||||
"typescript": "^4.9.3",
|
||||
"wait-on": "^6.0.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
-- RedefineTables
|
||||
PRAGMA foreign_keys=OFF;
|
||||
CREATE TABLE "new_Config" (
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
"key" TEXT NOT NULL PRIMARY KEY,
|
||||
"type" TEXT NOT NULL,
|
||||
"value" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"obscured" BOOLEAN NOT NULL DEFAULT false,
|
||||
"secret" BOOLEAN NOT NULL DEFAULT true,
|
||||
"locked" BOOLEAN NOT NULL DEFAULT false
|
||||
);
|
||||
INSERT INTO "new_Config" ("description", "key", "locked", "secret", "type", "updatedAt", "value") SELECT "description", "key", "locked", "secret", "type", "updatedAt", "value" FROM "Config";
|
||||
DROP TABLE "Config";
|
||||
ALTER TABLE "new_Config" RENAME TO "Config";
|
||||
PRAGMA foreign_key_check;
|
||||
PRAGMA foreign_keys=ON;
|
||||
@@ -84,6 +84,7 @@ model Config {
|
||||
type String
|
||||
value String
|
||||
description String
|
||||
obscured Boolean @default(false)
|
||||
secret Boolean @default(true)
|
||||
locked Boolean @default(false)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
import { Prisma, PrismaClient } from "@prisma/client";
|
||||
import * as crypto from "crypto";
|
||||
|
||||
const configVariables = [
|
||||
const configVariables: Prisma.ConfigCreateInput[] = [
|
||||
{
|
||||
key: "SETUP_FINISHED",
|
||||
description: "Whether the setup has been finished",
|
||||
@@ -55,7 +55,7 @@ const configVariables = [
|
||||
{
|
||||
key: "ENABLE_EMAIL_RECIPIENTS",
|
||||
description:
|
||||
"Whether to send emails to recipients. Only set this to true if you entered the host, port, email and password of your SMTP server.",
|
||||
"Whether to send emails to recipients. Only set this to true if you entered the host, port, email, user and password of your SMTP server.",
|
||||
type: "boolean",
|
||||
value: "false",
|
||||
secret: false,
|
||||
@@ -74,7 +74,13 @@ const configVariables = [
|
||||
},
|
||||
{
|
||||
key: "SMTP_EMAIL",
|
||||
description: "Email address of the SMTP server",
|
||||
description: "Email address which the emails get sent from",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
{
|
||||
key: "SMTP_USERNAME",
|
||||
description: "Username of the SMTP server",
|
||||
type: "string",
|
||||
value: "",
|
||||
},
|
||||
@@ -83,6 +89,7 @@ const configVariables = [
|
||||
description: "Password of the SMTP server",
|
||||
type: "string",
|
||||
value: "",
|
||||
obscured: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -102,14 +109,34 @@ async function main() {
|
||||
}
|
||||
}
|
||||
|
||||
// Delete the config variable if it doesn't exist anymore
|
||||
const configVariablesFromDatabase = await prisma.config.findMany();
|
||||
|
||||
// Delete the config variable if it doesn't exist anymore
|
||||
for (const configVariableFromDatabase of configVariablesFromDatabase) {
|
||||
if (!configVariables.find((v) => v.key == configVariableFromDatabase.key)) {
|
||||
const configVariable = configVariables.find(
|
||||
(v) => v.key == configVariableFromDatabase.key
|
||||
);
|
||||
if (!configVariable) {
|
||||
await prisma.config.delete({
|
||||
where: { key: configVariableFromDatabase.key },
|
||||
});
|
||||
|
||||
// Update the config variable if the metadata changed
|
||||
} else if (
|
||||
JSON.stringify({
|
||||
...configVariable,
|
||||
key: configVariableFromDatabase.key,
|
||||
value: configVariableFromDatabase.value,
|
||||
}) != JSON.stringify(configVariableFromDatabase)
|
||||
) {
|
||||
await prisma.config.update({
|
||||
where: { key: configVariableFromDatabase.key },
|
||||
data: {
|
||||
...configVariable,
|
||||
key: configVariableFromDatabase.key,
|
||||
value: configVariableFromDatabase.value,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@ export class AdminConfigDTO extends ConfigDTO {
|
||||
@Expose()
|
||||
description: string;
|
||||
|
||||
@Expose()
|
||||
obscured: boolean;
|
||||
|
||||
from(partial: Partial<AdminConfigDTO>) {
|
||||
return plainToClass(AdminConfigDTO, partial, {
|
||||
excludeExtraneousValues: true,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { IsNotEmpty } from "class-validator";
|
||||
import { IsNotEmpty, ValidateIf } from "class-validator";
|
||||
|
||||
class UpdateConfigDTO {
|
||||
@IsNotEmpty()
|
||||
@ValidateIf((dto) => dto.value !== "")
|
||||
value: string | number | boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ export class EmailService {
|
||||
port: parseInt(this.config.get("SMTP_PORT")),
|
||||
secure: parseInt(this.config.get("SMTP_PORT")) == 465,
|
||||
auth: {
|
||||
user: this.config.get("SMTP_EMAIL"),
|
||||
user: this.config.get("SMTP_USERNAME"),
|
||||
pass: this.config.get("SMTP_PASSWORD"),
|
||||
},
|
||||
});
|
||||
@@ -28,7 +28,7 @@ export class EmailService {
|
||||
from: `"Pingvin Share" <${this.config.get("SMTP_EMAIL")}>`,
|
||||
to: recipientEmail,
|
||||
subject: "Files shared with you",
|
||||
text: `Hey!\n${creator.username} shared some files with you. View or dowload the files with this link: ${shareUrl}.\n Shared securely with Pingvin Share 🐧`,
|
||||
text: `Hey!\n${creator.username} shared some files with you. View or dowload the files with this link: ${shareUrl}.\nShared securely with Pingvin Share 🐧`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { IsString } from "class-validator";
|
||||
import { IsOptional, IsString } from "class-validator";
|
||||
|
||||
export class SharePasswordDto {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
password: string;
|
||||
}
|
||||
|
||||
@@ -54,17 +54,20 @@ const AdminConfigTable = () => {
|
||||
<tbody>
|
||||
{isLoading
|
||||
? skeletonRows
|
||||
: configVariables.map((element) => (
|
||||
<tr key={element.key}>
|
||||
: configVariables.map((configVariable) => (
|
||||
<tr key={configVariable.key}>
|
||||
<td style={{ maxWidth: "200px" }}>
|
||||
<Code>{element.key}</Code> {element.secret && <TbLock />}{" "}
|
||||
<br />
|
||||
<Code>{configVariable.key}</Code>{" "}
|
||||
{configVariable.secret && <TbLock />} <br />
|
||||
<Text size="xs" color="dimmed">
|
||||
{element.description}
|
||||
{configVariable.description}
|
||||
</Text>
|
||||
</td>
|
||||
<td>{element.value}</td>
|
||||
|
||||
<td>
|
||||
{configVariable.obscured
|
||||
? "•".repeat(configVariable.value.length)
|
||||
: configVariable.value}
|
||||
</td>
|
||||
<td>
|
||||
<Group position="right">
|
||||
<ActionIcon
|
||||
@@ -74,7 +77,7 @@ const AdminConfigTable = () => {
|
||||
onClick={() =>
|
||||
showUpdateConfigVariableModal(
|
||||
modals,
|
||||
element,
|
||||
configVariable,
|
||||
getConfigVariables
|
||||
)
|
||||
}
|
||||
|
||||
@@ -50,7 +50,6 @@ const Body = ({
|
||||
<Stack>
|
||||
<form
|
||||
onSubmit={form.onSubmit(async (values) => {
|
||||
console.log(values);
|
||||
userService
|
||||
.create(values)
|
||||
.then(() => {
|
||||
@@ -62,10 +61,7 @@ const Body = ({
|
||||
>
|
||||
<Stack>
|
||||
<TextInput label="Username" {...form.getInputProps("username")} />
|
||||
<TextInput
|
||||
label="Email"
|
||||
{...form.getInputProps("email")}
|
||||
/>
|
||||
<TextInput label="Email" {...form.getInputProps("email")} />
|
||||
<PasswordInput
|
||||
label="New password"
|
||||
{...form.getInputProps("password")}
|
||||
|
||||
@@ -2,6 +2,7 @@ import {
|
||||
Button,
|
||||
Code,
|
||||
NumberInput,
|
||||
PasswordInput,
|
||||
Select,
|
||||
Space,
|
||||
Stack,
|
||||
@@ -53,9 +54,12 @@ const Body = ({
|
||||
<Text>
|
||||
Set <Code>{configVariable.key}</Code> to
|
||||
</Text>
|
||||
{configVariable.type == "string" && (
|
||||
<TextInput label="Value" {...form.getInputProps("stringValue")} />
|
||||
)}
|
||||
{configVariable.type == "string" &&
|
||||
(configVariable.obscured ? (
|
||||
<PasswordInput label="Value" {...form.getInputProps("stringValue")} />
|
||||
) : (
|
||||
<TextInput label="Value" {...form.getInputProps("stringValue")} />
|
||||
))}
|
||||
{configVariable.type == "number" && (
|
||||
<NumberInput label="Value" {...form.getInputProps("numberValue")} />
|
||||
)}
|
||||
|
||||
@@ -79,10 +79,7 @@ const Body = ({
|
||||
label="Username"
|
||||
{...accountForm.getInputProps("username")}
|
||||
/>
|
||||
<TextInput
|
||||
label="Email"
|
||||
{...accountForm.getInputProps("email")}
|
||||
/>
|
||||
<TextInput label="Email" {...accountForm.getInputProps("email")} />
|
||||
<Switch
|
||||
mt="xs"
|
||||
labelPosition="left"
|
||||
|
||||
@@ -29,8 +29,8 @@ const showCreateUploadModal = (
|
||||
modals: ModalsContextProps,
|
||||
options: {
|
||||
isUserSignedIn: boolean;
|
||||
ALLOW_UNAUTHENTICATED_SHARES: boolean;
|
||||
ENABLE_EMAIL_RECIPIENTS: boolean;
|
||||
allowUnauthenticatedShares: boolean;
|
||||
enableEmailRecepients: boolean;
|
||||
},
|
||||
uploadCallback: (
|
||||
id: string,
|
||||
@@ -62,15 +62,13 @@ const CreateUploadModalBody = ({
|
||||
) => void;
|
||||
options: {
|
||||
isUserSignedIn: boolean;
|
||||
ALLOW_UNAUTHENTICATED_SHARES: boolean;
|
||||
ENABLE_EMAIL_RECIPIENTS: boolean;
|
||||
allowUnauthenticatedShares: boolean;
|
||||
enableEmailRecepients: boolean;
|
||||
};
|
||||
}) => {
|
||||
const modals = useModals();
|
||||
|
||||
const [showNotSignedInAlert, setShowNotSignedInAlert] = useState(
|
||||
options.ENABLE_EMAIL_RECIPIENTS
|
||||
);
|
||||
const [showNotSignedInAlert, setShowNotSignedInAlert] = useState(true);
|
||||
|
||||
const validationSchema = yup.object().shape({
|
||||
link: yup
|
||||
@@ -230,7 +228,7 @@ const CreateUploadModalBody = ({
|
||||
{ExpirationPreview({ form })}
|
||||
</Text>
|
||||
<Accordion>
|
||||
{options.ENABLE_EMAIL_RECIPIENTS && (
|
||||
{options.enableEmailRecepients && (
|
||||
<Accordion.Item value="recipients" sx={{ borderBottom: "none" }}>
|
||||
<Accordion.Control>Email recipients</Accordion.Control>
|
||||
<Accordion.Panel>
|
||||
|
||||
@@ -80,10 +80,7 @@ const Account = () => {
|
||||
label="Username"
|
||||
{...accountForm.getInputProps("username")}
|
||||
/>
|
||||
<TextInput
|
||||
label="Email"
|
||||
{...accountForm.getInputProps("email")}
|
||||
/>
|
||||
<TextInput label="Email" {...accountForm.getInputProps("email")} />
|
||||
<Group position="right">
|
||||
<Button type="submit">Save</Button>
|
||||
</Group>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Col, Container, createStyles, Grid, Paper, Text } from "@mantine/core";
|
||||
import { Col, createStyles, Grid, Paper, Text } from "@mantine/core";
|
||||
import Link from "next/link";
|
||||
import { TbSettings, TbUsers } from "react-icons/tb";
|
||||
|
||||
@@ -34,28 +34,26 @@ const Admin = () => {
|
||||
const { classes, theme } = useStyles();
|
||||
|
||||
return (
|
||||
<Container size="xl">
|
||||
<Paper withBorder radius="md" p={40}>
|
||||
<Grid mt="md">
|
||||
{managementOptions.map((item) => {
|
||||
return (
|
||||
<Col xs={6} key={item.route}>
|
||||
<Paper
|
||||
withBorder
|
||||
component={Link}
|
||||
href={item.route}
|
||||
key={item.title}
|
||||
className={classes.item}
|
||||
>
|
||||
<item.icon color={theme.colors.victoria[5]} size={35} />
|
||||
<Text mt={7}>{item.title}</Text>
|
||||
</Paper>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</Paper>
|
||||
</Container>
|
||||
<Paper withBorder p={40}>
|
||||
<Grid mt="md">
|
||||
{managementOptions.map((item) => {
|
||||
return (
|
||||
<Col xs={6} key={item.route}>
|
||||
<Paper
|
||||
withBorder
|
||||
component={Link}
|
||||
href={item.route}
|
||||
key={item.title}
|
||||
className={classes.item}
|
||||
>
|
||||
<item.icon color={theme.colors.victoria[8]} size={35} />
|
||||
<Text mt={7}>{item.title}</Text>
|
||||
</Paper>
|
||||
</Col>
|
||||
);
|
||||
})}
|
||||
</Grid>
|
||||
</Paper>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -105,21 +105,19 @@ const Upload = () => {
|
||||
<Button
|
||||
loading={isUploading}
|
||||
disabled={files.length <= 0}
|
||||
onClick={() =>
|
||||
onClick={() => {
|
||||
showCreateUploadModal(
|
||||
modals,
|
||||
{
|
||||
isUserSignedIn: user ? true : false,
|
||||
ALLOW_UNAUTHENTICATED_SHARES: config.get(
|
||||
allowUnauthenticatedShares: config.get(
|
||||
"ALLOW_UNAUTHENTICATED_SHARES"
|
||||
),
|
||||
ENABLE_EMAIL_RECIPIENTS: config.get(
|
||||
"ENABLE_EMAIL_RECIPIENTS"
|
||||
),
|
||||
enableEmailRecepients: config.get("ENABLE_EMAIL_RECIPIENTS"),
|
||||
},
|
||||
uploadFiles
|
||||
)
|
||||
}
|
||||
);
|
||||
}}
|
||||
>
|
||||
Share
|
||||
</Button>
|
||||
|
||||
@@ -21,7 +21,7 @@ const completeShare = async (id: string) => {
|
||||
};
|
||||
|
||||
const get = async (id: string): Promise<Share> => {
|
||||
const shareToken = localStorage.getItem(`share_${id}_token`);
|
||||
const shareToken = sessionStorage.getItem(`share_${id}_token`);
|
||||
return (
|
||||
await api.get(`shares/${id}`, {
|
||||
headers: { "X-Share-Token": shareToken ?? "" },
|
||||
@@ -30,7 +30,7 @@ const get = async (id: string): Promise<Share> => {
|
||||
};
|
||||
|
||||
const getMetaData = async (id: string): Promise<ShareMetaData> => {
|
||||
const shareToken = localStorage.getItem(`share_${id}_token`);
|
||||
const shareToken = sessionStorage.getItem(`share_${id}_token`);
|
||||
return (
|
||||
await api.get(`shares/${id}/metaData`, {
|
||||
headers: { "X-Share-Token": shareToken ?? "" },
|
||||
@@ -49,7 +49,7 @@ const getMyShares = async (): Promise<MyShare[]> => {
|
||||
const getShareToken = async (id: string, password?: string) => {
|
||||
const { token } = (await api.post(`/shares/${id}/token`, { password })).data;
|
||||
|
||||
localStorage.setItem(`share_${id}_token`, token);
|
||||
sessionStorage.setItem(`share_${id}_token`, token);
|
||||
};
|
||||
|
||||
const isShareIdAvailable = async (id: string): Promise<boolean> => {
|
||||
@@ -57,7 +57,7 @@ const isShareIdAvailable = async (id: string): Promise<boolean> => {
|
||||
};
|
||||
|
||||
const getFileDownloadUrl = async (shareId: string, fileId: string) => {
|
||||
const shareToken = localStorage.getItem(`share_${shareId}_token`);
|
||||
const shareToken = sessionStorage.getItem(`share_${shareId}_token`);
|
||||
return (
|
||||
await api.get(`shares/${shareId}/files/${fileId}/download`, {
|
||||
headers: { "X-Share-Token": shareToken ?? "" },
|
||||
|
||||
@@ -8,6 +8,7 @@ export type AdminConfig = Config & {
|
||||
updatedAt: Date;
|
||||
secret: boolean;
|
||||
description: string;
|
||||
obscured: boolean;
|
||||
};
|
||||
|
||||
export default Config;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "pingvin-share",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.3",
|
||||
"scripts": {
|
||||
"format": "cd frontend && npm run format && cd ../backend && npm run format",
|
||||
"lint": "cd frontend && npm run lint && cd ../backend && npm run lint",
|
||||
|
||||
Reference in New Issue
Block a user