Compare commits
No commits in common. "dd1aab37d0e85790b7f64d4dfcf704081519b062" and "f3f36938df4095c4885fbddac51c632f23b2e181" have entirely different histories.
dd1aab37d0
...
f3f36938df
|
@ -0,0 +1,6 @@
|
|||
.git
|
||||
.editorconfig
|
||||
docker-minecraft.png
|
||||
LICENSE
|
||||
Makefile
|
||||
README.md
|
|
@ -0,0 +1,16 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{yaml,yml}]
|
||||
indent_size = 2
|
||||
|
||||
[Makefile]
|
||||
indent_size = 4
|
||||
indent_style = tab
|
25
.eslintrc.js
25
.eslintrc.js
|
@ -1,25 +0,0 @@
|
|||
module.exports = {
|
||||
env: {
|
||||
es2021: true,
|
||||
node: true
|
||||
},
|
||||
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: {
|
||||
ecmaVersion: 'latest',
|
||||
sourceType: 'module'
|
||||
},
|
||||
plugins: ['@typescript-eslint', 'prettier'],
|
||||
rules: {
|
||||
yoda: 'error',
|
||||
eqeqeq: 'error',
|
||||
complexity: 'error',
|
||||
'prefer-const': 'error',
|
||||
'prefer-template': 'error',
|
||||
'object-shorthand': 'warn',
|
||||
'prettier/prettier': 'warn',
|
||||
'prefer-destructuring': 'warn',
|
||||
'prefer-arrow-callback': 'error',
|
||||
'@typescript-eslint/no-namespace': 'off'
|
||||
}
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
github: PHLAK
|
||||
patreon: PHLAK
|
||||
custom: https://paypal.me/ChrisKankiewicz
|
|
@ -0,0 +1,8 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: docker
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: monthly
|
||||
timezone: US/Arizona
|
||||
open-pull-requests-limit: 10
|
|
@ -0,0 +1,40 @@
|
|||
name: Publish Image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ['master']
|
||||
tags: ['*']
|
||||
|
||||
env:
|
||||
DOCKER_HUB_USER: phlak
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
name: Build & Push
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Log in to Docker Hub
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
username: ${{ env.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_TOKEN }}
|
||||
|
||||
- name: Extract Metadata
|
||||
id: extract-metadata
|
||||
uses: docker/metadata-action@v3
|
||||
with:
|
||||
images: ${{ env.DOCKER_HUB_USER }}/minecraft
|
||||
tags: |
|
||||
type=raw,value=latest
|
||||
type=ref,event=tag
|
||||
|
||||
- name: Build & Push Image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.extract-metadata.outputs.tags }}
|
||||
labels: ${{ steps.extract-metadata.outputs.labels }}
|
|
@ -0,0 +1,15 @@
|
|||
name: Tests
|
||||
|
||||
on: [pull_request_target]
|
||||
|
||||
jobs:
|
||||
build-image:
|
||||
name: Build Image
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build Image
|
||||
run: make build
|
|
@ -1,4 +1,3 @@
|
|||
node_modules/
|
||||
dist/
|
||||
.env
|
||||
README.md
|
||||
data/
|
||||
db/
|
||||
files/server.jar
|
12
.prettierrc
12
.prettierrc
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"singleQuote": true,
|
||||
"arrowParens": "avoid",
|
||||
"bracketSpacing": true,
|
||||
"semi": true,
|
||||
"printWidth": 100,
|
||||
"trailingComma": "none",
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
|
50
Dockerfile
50
Dockerfile
|
@ -1,23 +1,49 @@
|
|||
FROM node:18-alpine
|
||||
FROM alpine:3.16.0
|
||||
LABEL maintainer='Andriy Cherniy <qugalet@m0e.space>'
|
||||
|
||||
WORKDIR /app
|
||||
# Minecraft version
|
||||
ARG MC_VERSION=bta
|
||||
ARG MC_JAR_SHA1=8399e1211e95faa421c1507b322dbeae86d604df
|
||||
|
||||
COPY ./package.json ./
|
||||
# Set default JVM options
|
||||
ENV _JAVA_OPTIONS '-Xms256M -Xmx4G'
|
||||
ARG JAVA_VERSION=19
|
||||
|
||||
RUN npm i
|
||||
# Create Minecraft directories
|
||||
RUN mkdir -pv /opt/minecraft /etc/minecraft
|
||||
|
||||
COPY ./.env ./
|
||||
# Create non-root user
|
||||
RUN adduser -DHs /sbin/nologin minecraft
|
||||
|
||||
COPY ./prisma/schema.prisma ./
|
||||
# Add the EULA file
|
||||
COPY files/eula.txt /etc/minecraft/eula.txt
|
||||
|
||||
RUN npm run migrate
|
||||
# Add the ops script
|
||||
COPY files/ops /usr/local/bin/ops
|
||||
RUN chmod +x /usr/local/bin/ops
|
||||
|
||||
RUN npm run generate
|
||||
# Install dependencies, fetch Minecraft server jar file and chown files
|
||||
#ARG JAR_URL=https://launcher.mojang.com/v1/objects/${MC_JAR_SHA1}/server.jar
|
||||
RUN apk add --update ca-certificates nss tzdata wget \
|
||||
&& apk add openjdk19-jre \
|
||||
#&& wget -O /opt/minecraft/minecraft_server.jar ${JAR_URL} \
|
||||
#&& apk del --purge wget && rm -rf /var/cache/apk/* \
|
||||
&& rm -rf /var/cache/apk/* \
|
||||
&& chown -R minecraft:minecraft /etc/minecraft /opt/minecraft
|
||||
|
||||
COPY . .
|
||||
COPY files/server.jar /opt/minecraft/minecraft_server.jar
|
||||
|
||||
RUN npm run build
|
||||
# Define volumes
|
||||
VOLUME /etc/minecraft
|
||||
|
||||
EXPOSE 8080
|
||||
# Expose port
|
||||
EXPOSE 25565
|
||||
|
||||
CMD ["node", "dist"]
|
||||
# Set running user
|
||||
USER minecraft
|
||||
|
||||
# Set the working dir
|
||||
WORKDIR /etc/minecraft
|
||||
|
||||
# Default run command
|
||||
CMD ["java", "-jar", "/opt/minecraft/minecraft_server.jar", "nogui"]
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2021 Chris Kankiewicz <Chris@ChrisKankiewicz.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
|
@ -0,0 +1,8 @@
|
|||
IMAGE_NAME="phlak/minecraft"
|
||||
IMAGE_TAG="$$(grep 'ARG MC_VERSION' Dockerfile | awk -F = '{print $$2}')"
|
||||
|
||||
build:
|
||||
@docker build --force-rm --pull --tag $(IMAGE_NAME):$(IMAGE_TAG) .
|
||||
|
||||
purge:
|
||||
@docker image rm --force $(IMAGE_NAME):$(IMAGE_TAG)
|
|
@ -0,0 +1,123 @@
|
|||
docker-minecraft
|
||||
================
|
||||
|
||||
<p align="center">
|
||||
<img src="docker-minecraft.png" alt="Docker Minecraft" width="500">
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/PHLAK/docker-minecraft/discussions"><img src="https://img.shields.io/badge/Join_the-Community-7b16ff.svg?style=for-the-badge" alt="Join the Community"></a>
|
||||
<a href="https://github.com/users/PHLAK/sponsorship"><img src="https://img.shields.io/badge/Become_a-Sponsor-cc4195.svg?style=for-the-badge" alt="Become a Sponsor"></a>
|
||||
<a href="https://paypal.me/ChrisKankiewicz"><img src="https://img.shields.io/badge/Make_a-Donation-006bb6.svg?style=for-the-badge" alt="One-time Donation"></a>
|
||||
<br>
|
||||
<a href="https://hub.docker.com/repository/docker/phlak/minecraft/tags"><img alt="Docker Image Version" src="https://img.shields.io/docker/v/phlak/minecraft?style=flat-square&sort=semver"></a>
|
||||
<a href="https://hub.docker.com/repository/docker/phlak/minecraft"><img alt="Docker Pulls" src="https://img.shields.io/docker/pulls/phlak/minecraft?style=flat-square"></a>
|
||||
<a href="https://github.com/PHLAK/docker-minecraft/blob/master/LICENSE"><img src="https://img.shields.io/github/license/PHLAK/docker-minecraft?style=flat-square" alt="License"></a>
|
||||
<a href="https://hub.docker.com/r/phlak/minecraft/builds"><img alt="Docker Cloud Build Status" src="https://img.shields.io/docker/cloud/build/phlak/minecraft"></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Docker image for <a href="https://minecraft.net/">Minecraft</a> server.
|
||||
</p>
|
||||
|
||||
---
|
||||
|
||||
Running the Container
|
||||
---------------------
|
||||
|
||||
First create a named data volume to hold the persistent world and config data:
|
||||
|
||||
docker volume create --name minecraft-data
|
||||
|
||||
Then run the Minecraft server:
|
||||
|
||||
docker run -it -d -p 25565:25565 -v minecraft-data:/etc/minecraft --name minecraft-server phlak/minecraft
|
||||
|
||||
#### Optional 'docker run' Arguments
|
||||
|
||||
<dl>
|
||||
<dt><code>-e _JAVA_OPTIONS='-Xms256M -Xmx2048M'</code></dt>
|
||||
<dd>Set JVM arguments for minimum/maximum memory consumption (default: '-Xms256M -Xmx2048M')</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt><code>-e TZ=America/Phoenix</code></dt>
|
||||
<dd>Set the timezone for your server. You can find your timezone in this <a href="https://goo.gl/uy1J6q">list of timezones</a>. Use the (case sensitive) value from the <code>TZ</code> column. If left unset, timezone will be UTC.</dd>
|
||||
</dl>
|
||||
|
||||
<dl>
|
||||
<dt><code>--restart unless-stopped</code></dt>
|
||||
<dd>Always restart the container regardless of the exit status, but do not start it on daemon startup if the container has been put to a stopped state before. See the Docker <a href="https://goo.gl/Y0dlDH">restart policies</a> for additional details.</dd>
|
||||
</dl>
|
||||
|
||||
**NOTE:** See the [Minecraft Wiki](http://minecraft.gamepedia.com/Server/Requirements) for more info
|
||||
on memory requirements.
|
||||
|
||||
Editing the Server Config
|
||||
-------------------------
|
||||
|
||||
Once you have a running container, you can edit the Minecraft [server config](https://minecraft.gamepedia.com/Server.properties) with:
|
||||
|
||||
docker exec -it minecraft-server vi /etc/minecraft/server.properties
|
||||
|
||||
After saving changes, restart your container with `docker restart minecraft-server`
|
||||
|
||||
Adding OPs
|
||||
----------
|
||||
|
||||
Once you have a running server container you can add OPs by running:
|
||||
|
||||
docker exec minecraft-server ops [PLAYER_NAMES]
|
||||
|
||||
**NOTE:** Replace `[PLAYER_NAMES]` with the name of one or more players you wish to give OP
|
||||
privileges separated by a space. If a players name contains spaces wrap it in quotation marks.
|
||||
|
||||
Here's an example granting OP to three players with name's `Marty`, `Jennifer` and `Doc Brown`:
|
||||
|
||||
docker exec minecraft-server ops Marty Jennifer "Doc Brown"
|
||||
|
||||
Running Server Commands
|
||||
-----------------------
|
||||
|
||||
You can run [commands](https://minecraft.gamepedia.com/Commands) on the server
|
||||
(e.g. `kick`, `ban`, `say`, etc.) by attaching to the running container and
|
||||
running the commands. Attach to the server by running:
|
||||
|
||||
docker attach minecraft-server
|
||||
|
||||
Once attached you can run your commands like normal.
|
||||
|
||||
say Hello world!
|
||||
[10:11:56] [Server thread/INFO]: [Server] Hello world!
|
||||
list
|
||||
[10:12:08] [Server thread/INFO]: There are 3 of a max 10 players online: Marty, Jennifer, Doc Brown
|
||||
seed
|
||||
[10:12:19] [Server thread/INFO]: Seed: [-5234790158571010769]
|
||||
|
||||
**NOTE:** In order to detach from the container and leave it running use the
|
||||
`Ctrl + P` then `Ctrl + Q` key sequence.
|
||||
|
||||
Upgrading the Server
|
||||
--------------------
|
||||
|
||||
First pull down the latest image:
|
||||
|
||||
docker pull phlak/minecraft
|
||||
|
||||
Remove your running server container:
|
||||
|
||||
docker rm -f minecraft-server
|
||||
|
||||
And run a new one with the same command/arguments as before.
|
||||
|
||||
Troubleshooting
|
||||
---------------
|
||||
|
||||
For general help and support join our [GitHub Discussions](https://github.com/PHLAK/docker-minecraft/discussions) or reach out on [Twitter](https://twitter.com/PHLAK).
|
||||
|
||||
Please report bugs to the [GitHub Issue Tracker](https://github.com/PHLAK/docker-minecraft/issues).
|
||||
|
||||
Copyright
|
||||
---------
|
||||
|
||||
This project is licensed under the [MIT License](https://github.com/PHLAK/docker-minecraft/blob/master/LICENSE).
|
|
@ -0,0 +1,12 @@
|
|||
* Minecraft Docker
|
||||
Dockerfile and docker-compose for your own server jar
|
||||
|
||||
** Usage
|
||||
Change your JAVA_VERSION in [[./Dockerfile][Dockerfile]] and build:
|
||||
#+BEGIN_SRC shell
|
||||
docker compose build
|
||||
#+END_SRC
|
||||
Place server.jar to ~files/~ folder, change your [[./docker-compose.yml][Docker Compose]] file and run:
|
||||
#+BEGIN_SRC shell
|
||||
docker compose up -d
|
||||
#+END_SRC
|
|
@ -1,9 +1,28 @@
|
|||
version: '2'
|
||||
services:
|
||||
backend:
|
||||
build: .
|
||||
db:
|
||||
image: postgres
|
||||
volumes:
|
||||
- ./db:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_DB=rpz_auth
|
||||
- POSTGRES_USER=postgres
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
|
||||
auth:
|
||||
build: ./auth
|
||||
depends_on:
|
||||
- db
|
||||
restart: unless-stopped
|
||||
|
||||
minecraft:
|
||||
build: .
|
||||
stdin_open: true # docker run -i
|
||||
tty: true # docker run -t
|
||||
restart: unless-stopped
|
||||
volumes:
|
||||
- ./data:/etc/minecraft
|
||||
ports:
|
||||
- '9030:8080'
|
||||
env_file:
|
||||
- ./.env
|
||||
- 25565:25565
|
||||
depends_on:
|
||||
- db
|
||||
- auth
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 38 KiB |
|
@ -0,0 +1 @@
|
|||
eula=true
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env sh
|
||||
set -o errexit
|
||||
|
||||
OPS_FILE="/etc/minecraft/ops.txt"
|
||||
[ ! -e "${OPS_FILE}" ] && touch ${OPS_FILE}
|
||||
|
||||
for OP in "$@"; do
|
||||
if grep -qx "${OP}" ${OPS_FILE}; then
|
||||
echo "NOTICE: '${OP}' already present in OPs file"; continue
|
||||
fi
|
||||
|
||||
echo "${OP}" >> ${OPS_FILE} && echo "SUCCESS: '${OP}' added to OPs file"
|
||||
done
|
40
package.json
40
package.json
|
@ -1,40 +0,0 @@
|
|||
{
|
||||
"name": "rpz_auth",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"generate": "prisma generate",
|
||||
"migrate": "prisma migrate deploy",
|
||||
"build": "rm -rf dist/** && tsc",
|
||||
"dev": "tsc -w",
|
||||
"start": "node ./dist"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@tsconfig/node18": "^1.0.1",
|
||||
"@types/jsonwebtoken": "^8.5.9",
|
||||
"@types/node": "^18.7.13",
|
||||
"@typescript-eslint/eslint-plugin": "^5.36.0",
|
||||
"@typescript-eslint/parser": "^5.35.1",
|
||||
"eslint": "^8.23.0",
|
||||
"eslint-plugin-prettier": "^4.2.1",
|
||||
"prettier": "^2.7.1",
|
||||
"typescript": "^4.8.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fastify/autoload": "^5.2.0",
|
||||
"@fastify/cookie": "^8.1.0",
|
||||
"@prisma/client": "^4.2.1",
|
||||
"axios": "^0.27.2",
|
||||
"fastify": "^4.5.3",
|
||||
"json-schema-to-ts": "^2.5.5",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"nanoid": "3",
|
||||
"prisma": "^4.3.0",
|
||||
"redis": "^4.3.0",
|
||||
"simple-oauth2": "^4.3.0"
|
||||
}
|
||||
}
|
1694
pnpm-lock.yaml
1694
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
|
@ -1,23 +0,0 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"nickname" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Session" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userNickname" TEXT NOT NULL,
|
||||
"ip" TEXT NOT NULL,
|
||||
"expiredAfter" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Session_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_nickname_key" ON "User"("nickname");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Session" ADD CONSTRAINT "Session_userNickname_fkey" FOREIGN KEY ("userNickname") REFERENCES "User"("nickname") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -1,5 +0,0 @@
|
|||
-- AlterTable
|
||||
ALTER TABLE "Session" ADD COLUMN "verified" BOOLEAN NOT NULL DEFAULT false;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "User" ALTER COLUMN "nickname" DROP NOT NULL;
|
|
@ -1,13 +0,0 @@
|
|||
/*
|
||||
Warnings:
|
||||
|
||||
- You are about to drop the column `userNickname` on the `Session` table. All the data in the column will be lost.
|
||||
- Added the required column `nickname` to the `Session` table without a default value. This is not possible if the table is not empty.
|
||||
|
||||
*/
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "Session" DROP CONSTRAINT "Session_userNickname_fkey";
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Session" DROP COLUMN "userNickname",
|
||||
ADD COLUMN "nickname" TEXT NOT NULL;
|
|
@ -1,14 +0,0 @@
|
|||
-- CreateTable
|
||||
CREATE TABLE "Link" (
|
||||
"id" TEXT NOT NULL,
|
||||
"sessionId" TEXT NOT NULL,
|
||||
"link" TEXT NOT NULL,
|
||||
|
||||
CONSTRAINT "Link_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Link_sessionId_key" ON "Link"("sessionId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Link" ADD CONSTRAINT "Link_sessionId_fkey" FOREIGN KEY ("sessionId") REFERENCES "Session"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
|
@ -1,3 +0,0 @@
|
|||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (i.e. Git)
|
||||
provider = "postgresql"
|
|
@ -1,29 +0,0 @@
|
|||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id
|
||||
nickname String? @unique
|
||||
}
|
||||
|
||||
model Session {
|
||||
id String @id @default(uuid())
|
||||
nickname String
|
||||
ip String
|
||||
verified Boolean @default(false)
|
||||
expiredAfter DateTime
|
||||
link Link?
|
||||
}
|
||||
|
||||
model Link {
|
||||
id String @id
|
||||
session Session @relation(fields: [sessionId], references: [id])
|
||||
sessionId String @unique
|
||||
link String
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
import { PrismaClient } from '@prisma/client';
|
||||
import('nanoid').then(nanoid => {
|
||||
const db = new PrismaClient();
|
||||
|
||||
db.session
|
||||
.create({
|
||||
data: {
|
||||
id: nanoid.nanoid(10),
|
||||
ip: '127.0.0.1',
|
||||
nickname: 'Qugalet',
|
||||
expiredAfter: new Date(Date.now() + 604800)
|
||||
}
|
||||
})
|
||||
.then(session =>
|
||||
console.log(
|
||||
encodeURI(
|
||||
`https://auth.m0e.space/application/o/authorize/?client_id=7f24f967b2faf3d8c1c53771661abff8e07060c0&response_type=code&redirect_uri=http://localhost:8080/api/auth/verify?session=${session.id}&scope=profile openid`
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
68
src/index.ts
68
src/index.ts
|
@ -1,68 +0,0 @@
|
|||
import fastify from 'fastify';
|
||||
import fastifyAutoload from '@fastify/autoload';
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
// import { createClient, RedisClientType } from 'redis';
|
||||
// import fastifySchedule from '@fastify/schedule';
|
||||
// import fastifyCors from '@fastify/cors';
|
||||
|
||||
import path from 'path';
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyInstance {
|
||||
db: PrismaClient;
|
||||
// redis: RedisClientType;
|
||||
}
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace NodeJS {
|
||||
interface ProcessEnv {
|
||||
NODE_ENV: 'development' | 'production';
|
||||
PORT: number;
|
||||
JWT_REFRESH_SECRET: string;
|
||||
JWT_ACCESS_SECRET: string;
|
||||
AUTH_CLIENT_ID: string;
|
||||
AUTH_CLIENT_SECRET: string;
|
||||
REDIS_URL: string;
|
||||
URL_TOKEN: string;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fastify({
|
||||
logger: true,
|
||||
ajv: { customOptions: { allErrors: true } }
|
||||
})
|
||||
.decorate('db', new PrismaClient())
|
||||
// .decorate('redis', async () => {
|
||||
// const client = createClient({
|
||||
// url: process.env.REDIS_URL
|
||||
// });
|
||||
|
||||
// client.on('error', err => console.log('Redis Client Error', err));
|
||||
|
||||
// await client.connect();
|
||||
// return client;
|
||||
// })
|
||||
.addHook('onRoute', route => console.log(route.url))
|
||||
// .register(fastifyCors, {
|
||||
// origin: ['http://127.0.0.1:3000'],
|
||||
// credentials: true
|
||||
// })
|
||||
.register(fastifyAutoload, {
|
||||
dir: path.join(__dirname, 'routes'),
|
||||
routeParams: true,
|
||||
autoHooks: true,
|
||||
options: { prefix: '/api' }
|
||||
})
|
||||
.register(fastifyAutoload, {
|
||||
dir: path.join(__dirname, 'link'),
|
||||
routeParams: true,
|
||||
autoHooks: true,
|
||||
options: { prefix: '/a' }
|
||||
})
|
||||
.listen({ port: process.env.PORT || 8080, host: '0.0.0.0' })
|
||||
// eslint-disable-next-line no-console
|
||||
.then(() => console.log('Server Started'))
|
||||
// eslint-disable-next-line no-console
|
||||
.catch(console.error);
|
|
@ -1,76 +0,0 @@
|
|||
import { FastifyInstance } from 'fastify';
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { nanoid } from 'nanoid/async';
|
||||
|
||||
const schema = {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
required: ['session', 'key'],
|
||||
properties: {
|
||||
session: { type: 'string' },
|
||||
key: { type: 'string' }
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export default async (server: FastifyInstance) =>
|
||||
server.get<{ Querystring: FromSchema<typeof schema.querystring> }>(
|
||||
'/create',
|
||||
async (req, reply) => {
|
||||
if (req.query.key !== process.env.URL_TOKEN) return reply.code(403).send('Forbidden');
|
||||
const session = await server.db.session.findFirst({
|
||||
where: {
|
||||
id: req.query.session
|
||||
}
|
||||
});
|
||||
if (!session) return reply.code(404).send('Session is not found');
|
||||
const linkedSession = await server.db.link.findFirst({
|
||||
where: { session: { id: req.query.session } },
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
});
|
||||
if (linkedSession)
|
||||
reply.send(
|
||||
`${
|
||||
process.env.NODE_ENV === 'production'
|
||||
? 'https://mc.m0e.space/a'
|
||||
: 'http://localhost:8080/a'
|
||||
}/${linkedSession.id}`
|
||||
);
|
||||
let linkId = await nanoid(5);
|
||||
// eslint-disable-next-line no-constant-condition
|
||||
while (true) {
|
||||
const link = await server.db.link.findFirst({
|
||||
where: { id: linkId },
|
||||
select: { id: true }
|
||||
});
|
||||
if (!link) break;
|
||||
linkId = await nanoid(5);
|
||||
}
|
||||
await server.db.link.create({
|
||||
data: {
|
||||
id: linkId,
|
||||
link: encodeURI(
|
||||
`https://auth.m0e.space/application/o/authorize/?client_id=7f24f967b2faf3d8c1c53771661abff8e07060c0&response_type=code&redirect_uri=${
|
||||
process.env.NODE_ENV === 'production'
|
||||
? 'https://mc.m0e.space'
|
||||
: 'http://localhost:8080'
|
||||
}/api/auth/verify?session=${req.query.session}&scope=profile openid`
|
||||
),
|
||||
session: {
|
||||
connect: {
|
||||
id: req.query.session
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
reply.send(
|
||||
`${
|
||||
process.env.NODE_ENV === 'production'
|
||||
? 'https://mc.m0e.space/a'
|
||||
: 'http://localhost:8080/a'
|
||||
}/${linkId}`
|
||||
);
|
||||
}
|
||||
);
|
|
@ -1,9 +0,0 @@
|
|||
import { FastifyInstance } from 'fastify';
|
||||
|
||||
export default async (server: FastifyInstance) =>
|
||||
server.get<{ Params: { id: string } }>('/:id', (req, reply) =>
|
||||
server.db.link
|
||||
.findFirstOrThrow({ where: { id: req.params.id } })
|
||||
.then(link => reply.redirect(link.link))
|
||||
.catch(() => reply.code(404).send('URL not found'))
|
||||
);
|
|
@ -1,49 +0,0 @@
|
|||
import { FastifyInstance, FastifyReply } from 'fastify';
|
||||
import { CookieSerializeOptions } from '@fastify/cookie';
|
||||
import { User } from '@prisma/client';
|
||||
import jwt from 'jsonwebtoken';
|
||||
|
||||
const cookieSettings: CookieSerializeOptions = {
|
||||
httpOnly: true,
|
||||
path: '/api/auth/refresh_token',
|
||||
sameSite: 'strict',
|
||||
maxAge: 2629800, //1 month
|
||||
secure: process.env.NODE_ENV === 'production'
|
||||
};
|
||||
|
||||
declare module 'fastify' {
|
||||
interface FastifyReply {
|
||||
sendTokens: (user: User) => FastifyReply;
|
||||
clearTokens: () => FastifyReply;
|
||||
}
|
||||
}
|
||||
|
||||
export default async (server: FastifyInstance) =>
|
||||
server
|
||||
.decorateReply('sendTokens', function (this: FastifyReply, { id, nickname }: User) {
|
||||
return this.setCookie(
|
||||
'owo',
|
||||
jwt.sign({ tokenVersion: 0, id }, process.env.JWT_REFRESH_SECRET, {
|
||||
expiresIn: '30d'
|
||||
}),
|
||||
cookieSettings
|
||||
).send({
|
||||
user: {
|
||||
id,
|
||||
nickname
|
||||
},
|
||||
token: jwt.sign(
|
||||
{
|
||||
id,
|
||||
nickname
|
||||
},
|
||||
process.env.JWT_ACCESS_SECRET,
|
||||
{
|
||||
expiresIn: '15m'
|
||||
}
|
||||
)
|
||||
});
|
||||
})
|
||||
.decorateReply('clearTokens', function (this: FastifyReply) {
|
||||
return this.clearCookie('owo', cookieSettings);
|
||||
});
|
|
@ -1,88 +0,0 @@
|
|||
import { FastifyInstance } from 'fastify';
|
||||
import { FromSchema } from 'json-schema-to-ts';
|
||||
import { stringify } from 'querystring';
|
||||
import axios from 'axios';
|
||||
|
||||
const schema = {
|
||||
querystring: {
|
||||
type: 'object',
|
||||
required: ['code', 'session'],
|
||||
properties: {
|
||||
code: { type: 'string' },
|
||||
session: { type: 'string' }
|
||||
}
|
||||
}
|
||||
} as const;
|
||||
|
||||
export default async (server: FastifyInstance) =>
|
||||
server.get<{ Querystring: FromSchema<typeof schema.querystring> }>(
|
||||
'/verify',
|
||||
{ schema },
|
||||
(req, reply) => {
|
||||
axios
|
||||
.post(
|
||||
'https://auth.m0e.space/application/o/token/',
|
||||
stringify({
|
||||
client_id: process.env.AUTH_CLIENT_ID,
|
||||
client_secret: process.env.AUTH_CLIENT_SECRET,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri:
|
||||
process.env.NODE_ENV === 'production'
|
||||
? 'https://mc.m0e.space/api/auth/verify'
|
||||
: 'http://localhost:8080/api/auth/verify',
|
||||
code: req.query.code
|
||||
})
|
||||
)
|
||||
.then(res =>
|
||||
axios
|
||||
.get('https://auth.m0e.space/application/o/userinfo/', {
|
||||
headers: { Authorization: `Bearer ${res.data.access_token}` }
|
||||
})
|
||||
.then(async res => {
|
||||
const user =
|
||||
(await server.db.user.findFirst({ where: { id: res.data.sub } })) ||
|
||||
(await server.db.user.create({ data: { id: res.data.sub } }));
|
||||
const session = await server.db.session.findFirst({
|
||||
where: { id: req.query.session }
|
||||
});
|
||||
if (!session) return reply.code(400).send('Invalid session');
|
||||
const userByNickname = await server.db.user.findFirst({
|
||||
where: { nickname: session.nickname }
|
||||
});
|
||||
if (!userByNickname) {
|
||||
await Promise.all([
|
||||
server.db.user.update({
|
||||
where: { id: user.id },
|
||||
data: { nickname: session.nickname }
|
||||
}),
|
||||
server.db.session.update({
|
||||
where: { id: req.query.session },
|
||||
data: {
|
||||
verified: true
|
||||
}
|
||||
})
|
||||
]).then(() => reply.redirect('https://mc.m0e.space/message/success'));
|
||||
|
||||
// await server.redis.publish('rpz_auth', req.query.session);
|
||||
} else if (userByNickname.id !== user.id) reply.send(403).send('Forbidden');
|
||||
else
|
||||
await server.db.session
|
||||
.update({
|
||||
where: { id: req.query.session },
|
||||
data: {
|
||||
verified: true
|
||||
}
|
||||
})
|
||||
.then(() => reply.redirect('https://mc.m0e.space/message/success'));
|
||||
})
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reply.code(500).send(err);
|
||||
})
|
||||
)
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
reply.code(500).send(err);
|
||||
});
|
||||
}
|
||||
);
|
|
@ -1,9 +0,0 @@
|
|||
{
|
||||
"extends": "@tsconfig/node18/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist"
|
||||
// "module": "esnext"
|
||||
},
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true
|
||||
}
|
Loading…
Reference in New Issue