Compare commits
48
Commits
dev
...
58cadadf7f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58cadadf7f | ||
|
|
b36b19af27 | ||
|
|
909d3e9162 | ||
|
|
07b178b488 | ||
|
|
82cc3d396a | ||
|
|
acea25f536 | ||
|
|
2883cb6045 | ||
|
|
aeed25da38 | ||
|
|
a26fc340eb | ||
|
|
2e9ad750de | ||
|
|
f93d66c35b | ||
|
|
1acd6b67c4 | ||
|
|
89c12dace6 | ||
|
|
d115624d85 | ||
|
|
5e6f526446 | ||
|
|
d7427c55dd | ||
|
|
e05d1000f8 | ||
|
|
8437a82428 | ||
|
|
bfe848f335 | ||
|
|
0e70e7d2bc | ||
|
|
cce78fa8b3 | ||
|
|
e67fb2ffe2 | ||
|
|
98f505ce88 | ||
|
|
da850e6086 | ||
|
|
4aa6aad6cb | ||
|
|
eb476c0b9d | ||
|
|
dab959d1a5 | ||
|
|
3929678a43 | ||
|
|
ce46878054 | ||
|
|
1e29b2e624 | ||
|
|
d2b12d2e5a | ||
|
|
c25952bbc1 | ||
|
|
5b8f9bc1ab | ||
|
|
04d0e2ae31 | ||
|
|
4259295ba3 | ||
|
|
b98326f510 | ||
|
|
7db2a78c0b | ||
|
|
cbc6ff04f6 | ||
|
|
c7955ecee7 | ||
|
|
acede2104a | ||
|
|
5895990cbb | ||
|
|
320d4d7502 | ||
|
|
cc70057b63 | ||
|
|
dbe3b79fb5 | ||
|
|
0e56d9f1f8 | ||
|
|
b894e3a6f1 | ||
|
|
19433276af | ||
|
|
552fc6b9a8 |
+3
-1
@@ -1,2 +1,4 @@
|
||||
project_context.txt
|
||||
shagram.db
|
||||
shagram.db
|
||||
deploy/shagram/nginx/certs/*.pem
|
||||
deploy/shagram/.env
|
||||
+10
-8
@@ -1,20 +1,22 @@
|
||||
FROM golang:1.25.5-alpine AS builder
|
||||
|
||||
RUN apk add --no-cache build-base
|
||||
RUN apk add --no-cache build-base ca-certificates
|
||||
WORKDIR /app
|
||||
|
||||
COPY go.mod go.sum ./
|
||||
RUN go mod download
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
go mod download
|
||||
|
||||
COPY . .
|
||||
RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o shagram ./cmd/server
|
||||
RUN --mount=type=cache,target=/go/pkg/mod \
|
||||
--mount=type=cache,target=/root/.cache/go-build \
|
||||
CGO_ENABLED=1 GOOS=linux go build -o shagram ./cmd/server
|
||||
|
||||
FROM alpine:latest
|
||||
RUN apk --no-cache add ca-certificates sqlite-libs
|
||||
|
||||
RUN apk add --no-cache ca-certificates sqlite-libs sqlite
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/shagram .
|
||||
COPY static ./static
|
||||
COPY migrations ./migrations
|
||||
RUN mkdir -p /app/data
|
||||
|
||||
EXPOSE 8080
|
||||
CMD ["./shagram"]
|
||||
CMD ["./shagram"]
|
||||
|
||||
Vendored
+99
@@ -0,0 +1,99 @@
|
||||
pipeline {
|
||||
agent { label 'docker-agent' }
|
||||
|
||||
options {
|
||||
skipDefaultCheckout(true)
|
||||
timestamps()
|
||||
}
|
||||
|
||||
environment {
|
||||
REGISTRY = "158.160.92.116:8085"
|
||||
REGISTRY_PROJECT = "shagram"
|
||||
IMAGE_NAME = "shagram"
|
||||
DEPLOY_DIR = "/opt/shagram/shagram/deploy/shagram"
|
||||
COMPOSE_FILE = "${WORKSPACE}/deploy/shagram/compose.yaml"
|
||||
}
|
||||
|
||||
stages {
|
||||
stage('Checkout') {
|
||||
steps {
|
||||
checkout scm
|
||||
sh '''
|
||||
set -eux
|
||||
git reset --hard
|
||||
git clean -xffd
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Detect branch') {
|
||||
steps {
|
||||
script {
|
||||
env.GIT_BRANCH = sh(
|
||||
script: "git name-rev --name-only --refs=refs/remotes/origin/* HEAD | sed 's#^remotes/##' | head -n1",
|
||||
returnStdout: true
|
||||
).trim()
|
||||
echo "Detected branch: ${env.GIT_BRANCH}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build image') {
|
||||
steps {
|
||||
script {
|
||||
env.GIT_SHA = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
|
||||
// итоговый тег для Harbor
|
||||
env.APP_IMAGE = "${REGISTRY}/${REGISTRY_PROJECT}/${IMAGE_NAME}:${env.GIT_SHA}"
|
||||
}
|
||||
sh '''
|
||||
set -eux
|
||||
# собираем локальный образ без registry
|
||||
docker build -t "${IMAGE_NAME}:${GIT_SHA}" .
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Login & Push to Harbor') {
|
||||
steps {
|
||||
withCredentials([usernamePassword(
|
||||
credentialsId: 'harbor-creds',
|
||||
usernameVariable: 'HARBOR_USER',
|
||||
passwordVariable: 'HARBOR_PASS'
|
||||
)]) {
|
||||
sh '''
|
||||
set -eux
|
||||
echo "$HARBOR_PASS" | docker login "$REGISTRY" -u "$HARBOR_USER" --password-stdin
|
||||
docker tag "${IMAGE_NAME}:${GIT_SHA}" "${APP_IMAGE}"
|
||||
docker push "${APP_IMAGE}"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
stage('Test') {
|
||||
steps {
|
||||
sh 'echo "Testing..."'
|
||||
}
|
||||
}
|
||||
|
||||
stage('Deploy') {
|
||||
when {
|
||||
expression { env.GIT_BRANCH == 'origin/main' }
|
||||
}
|
||||
steps {
|
||||
sh '''
|
||||
set -eux
|
||||
|
||||
mkdir -p "$DEPLOY_DIR"
|
||||
cat > "$DEPLOY_DIR/.env" <<EOF
|
||||
APP_IMAGE=${APP_IMAGE}
|
||||
EOF
|
||||
|
||||
docker compose -f "$COMPOSE_FILE" --project-directory "$DEPLOY_DIR" pull
|
||||
docker compose -f "$COMPOSE_FILE" --project-directory "$DEPLOY_DIR" up -d --remove-orphans
|
||||
docker compose -f "$COMPOSE_FILE" --project-directory "$DEPLOY_DIR" ps
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-1
@@ -3,16 +3,23 @@ package main
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"shagram/internal/api"
|
||||
"shagram/internal/auth"
|
||||
"shagram/internal/db"
|
||||
"shagram/internal/models"
|
||||
"shagram/internal/websocket"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
database, err := db.NewDB("/app/data/shagram.db")
|
||||
dbPath := os.Getenv("DATABASE_PATH")
|
||||
if dbPath == "" {
|
||||
dbPath = "/app/data/shagram.db"
|
||||
}
|
||||
database, err := db.NewDB(dbPath)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
@@ -24,6 +31,27 @@ func main() {
|
||||
|
||||
router := gin.Default()
|
||||
|
||||
router.POST("/api/auth/login", func(c *gin.Context) {
|
||||
var req struct {
|
||||
Username string `json:"username"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil || req.Username == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "username required"})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := auth.NewAccessToken(req.Username, time.Hour)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{"access_token": token})
|
||||
})
|
||||
router.GET("/api/me", auth.Middleware(), func(c *gin.Context) {
|
||||
username := c.GetString(auth.CtxUsernameKey)
|
||||
c.JSON(200, gin.H{"username": username})
|
||||
})
|
||||
router.GET("/ws/:room", func(c *gin.Context) {
|
||||
api.WebSocketHandler(hub, database)(c)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
services:
|
||||
shagram:
|
||||
image: ${APP_IMAGE:-shagram:local}
|
||||
build:
|
||||
context: ../..
|
||||
container_name: shagram-app
|
||||
environment:
|
||||
- DATABASE_PATH=/app/data/shagram.db
|
||||
- JWT_SECRET=${JWT_SECRET}
|
||||
volumes:
|
||||
- shagram_data:/app/data
|
||||
expose:
|
||||
- "8080"
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
container_name: shagram-nginx
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/conf.d:/etc/nginx/conf.d:ro
|
||||
- ./nginx/certs:/etc/nginx/certs:ro
|
||||
depends_on:
|
||||
- shagram
|
||||
volumes:
|
||||
shagram_data:
|
||||
@@ -0,0 +1,34 @@
|
||||
# TLS Certificates for Nginx (Development / Self-Signed)
|
||||
|
||||
In production, TLS certificates are typically issued by a trusted Certificate Authority (for example, via Let’s Encrypt).
|
||||
For local development and demo environments, a self-signed certificate can be used.
|
||||
|
||||
## Generate a self-signed certificate (Linux/macOS)
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
mkdir -p deploy/shagram/nginx/certs
|
||||
|
||||
openssl req -x509 -newkey rsa:4096 \
|
||||
-keyout deploy/shagram/nginx/certs/key.pem \
|
||||
-out deploy/shagram/nginx/certs/cert.pem \
|
||||
-sha256 -days 365 -nodes \
|
||||
-subj "/C=RU/ST=Moscow/L=Korolyov/O=Shagram/CN=localhost"
|
||||
```
|
||||
|
||||
## Verify
|
||||
```bash
|
||||
openssl x509 -in deploy/shagram/nginx/certs/cert.pem -noout -text | head
|
||||
```
|
||||
|
||||
## Usage
|
||||
The Nginx configuration expects:
|
||||
- `deploy/shagram/nginx/certs/cert.pem`
|
||||
- `deploy/shagram/nginx/certs/key.pem`
|
||||
|
||||
Start the deployment:
|
||||
|
||||
```bash
|
||||
cd deploy/shagram
|
||||
docker compose up -d
|
||||
```
|
||||
@@ -1,26 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
shagram:
|
||||
build: .
|
||||
ports:
|
||||
- "8080"
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./static:/app/static
|
||||
- ./migrations:/app/migrations
|
||||
environment:
|
||||
- DATABASE_PATH=/app/shagram.db
|
||||
container_name: shagram-app
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
volumes:
|
||||
- ./nginx/conf.d/default.conf:/etc/nginx/conf.d/default.conf
|
||||
- ./nginx/certs:/etc/nginx/certs
|
||||
depends_on:
|
||||
- shagram
|
||||
container_name: shagram-nginx
|
||||
@@ -14,6 +14,7 @@ require (
|
||||
github.com/go-playground/validator/v10 v10.27.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-yaml v1.18.0 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
|
||||
github.com/gorilla/websocket v1.5.3 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
|
||||
@@ -22,6 +22,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
|
||||
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg=
|
||||
github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# Jenkins (Controller + Docker Agent) Setup (Docker Compose)
|
||||
|
||||
This directory contains a minimal Jenkins setup using a dedicated **controller** and a separate inbound **agent** intended for Docker-based workloads.
|
||||
|
||||
The goal is to keep the controller responsible for orchestration and configuration, while all builds run on the agent labeled `docker`.
|
||||
|
||||
## Prerequisites
|
||||
- Docker Engine installed on the host
|
||||
- Docker Compose available as `docker compose`
|
||||
- A host directory `/opt/shagram` (used by pipelines as a shared location for source code and deployment files)
|
||||
|
||||
## Start Jenkins
|
||||
From the repository root:
|
||||
|
||||
```bash
|
||||
cd infra/jenkins
|
||||
docker compose up -d
|
||||
docker compose ps
|
||||
```
|
||||
|
||||
Jenkins UI will be available at:
|
||||
|
||||
- http://<server-ip>:8080
|
||||
|
||||
### Initial admin password
|
||||
Retrieve the initial password with:
|
||||
|
||||
```bash
|
||||
docker exec -it jenkins-controller cat /var/jenkins_home/secrets/initialAdminPassword
|
||||
```
|
||||
|
||||
## Disable builds on the built-in node (Executors = 0)
|
||||
To ensure builds do not run on the controller:
|
||||
|
||||
1. Open Jenkins UI
|
||||
2. Go to: **Manage Jenkins → Manage Nodes and Clouds**
|
||||
3. Open **Built-In Node → Configure**
|
||||
4. Set **Number of executors** to `0`
|
||||
5. Save
|
||||
|
||||
## Create an inbound agent node (docker-agent)
|
||||
Create a dedicated node for running pipelines:
|
||||
|
||||
1. Go to: **Manage Jenkins → Manage Nodes and Clouds → New Node**
|
||||
2. Set:
|
||||
- **Node name**: `docker-agent`
|
||||
- **Type**: Permanent Agent
|
||||
- **Remote root directory**: `/home/jenkins/agent`
|
||||
- **Labels**: `docker`
|
||||
- **Usage**: Only build jobs with label expressions matching this node
|
||||
3. Save
|
||||
|
||||
After saving, open the agent page:
|
||||
|
||||
- **Manage Nodes and Clouds → docker-agent**
|
||||
|
||||
On that page, Jenkins provides the inbound connection details, including the **secret** required by the inbound agent container.
|
||||
|
||||
## Configure the agent secret in Compose
|
||||
Edit `infra/jenkins/compose.yaml` and replace:
|
||||
|
||||
- `JENKINS_SECRET=__PASTE_ME__`
|
||||
|
||||
with the real secret value shown on the `docker-agent` node page.
|
||||
|
||||
Restart only the agent container:
|
||||
|
||||
```bash
|
||||
docker compose up -d --force-recreate jenkins-agent-docker
|
||||
docker logs -f jenkins-agent-docker
|
||||
```
|
||||
|
||||
## Verification
|
||||
- In Jenkins UI: **Manage Nodes and Clouds**, the node `docker-agent` should be **Online**
|
||||
- Any pipeline using `agent { label 'docker' }` should execute on this agent
|
||||
|
||||
## Security note
|
||||
The Docker agent container mounts `/var/run/docker.sock`, which effectively grants high-level control over the Docker host. Use this setup only in trusted environments and limit access to Jenkins accordingly.
|
||||
@@ -0,0 +1,37 @@
|
||||
services:
|
||||
jenkins-controller:
|
||||
image: jenkins/jenkins:lts-jdk17
|
||||
container_name: jenkins-controller
|
||||
ports:
|
||||
- "8080:8080"
|
||||
volumes:
|
||||
- jenkins_home:/var/jenkins_home
|
||||
restart: unless-stopped
|
||||
|
||||
jenkins-agent-docker:
|
||||
image: jenkins/inbound-agent:latest-jdk17
|
||||
container_name: jenkins-agent-docker
|
||||
user: "1000:1000"
|
||||
group_add:
|
||||
- "988"
|
||||
environment:
|
||||
- JENKINS_URL=http://jenkins-controller:8080
|
||||
- JENKINS_AGENT_NAME=docker-agent
|
||||
- JENKINS_SECRET=0c92dc0b807b3c7213cd2abcec4f88182aa8f4fb2233ca9c674f17fd771fe662
|
||||
- AGENT_WORKDIR=/home/jenkins/agent
|
||||
volumes:
|
||||
- agent_workdir:/home/jenkins/agent
|
||||
- /var/run/docker.sock:/var/run/docker.sock
|
||||
- /usr/bin/docker:/usr/bin/docker
|
||||
- /usr/libexec/docker/cli-plugins:/usr/libexec/docker/cli-plugins:ro
|
||||
- /opt/shagram:/opt/shagram
|
||||
|
||||
restart: unless-stopped
|
||||
depends_on:
|
||||
- jenkins-controller
|
||||
|
||||
volumes:
|
||||
jenkins_home:
|
||||
external: true
|
||||
name: jenkins_jenkins_home
|
||||
agent_workdir:
|
||||
@@ -0,0 +1,64 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
type Claims struct {
|
||||
Username string `json:"username"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
func secret() ([]byte, error) {
|
||||
s := os.Getenv("JWT_SECRET")
|
||||
if s == "" {
|
||||
return nil, errors.New("JWT_SECRET is not set")
|
||||
}
|
||||
return []byte(s), nil
|
||||
}
|
||||
|
||||
func NewAccessToken(username string, ttl time.Duration) (string, error) {
|
||||
key, err := secret()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
now := time.Now()
|
||||
claims := Claims{
|
||||
Username: username,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
Subject: username,
|
||||
IssuedAt: jwt.NewNumericDate(now),
|
||||
ExpiresAt: jwt.NewNumericDate(now.Add(ttl)),
|
||||
},
|
||||
}
|
||||
|
||||
t := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
return t.SignedString(key)
|
||||
}
|
||||
|
||||
func ParseAccessToken(tokenString string) (*Claims, error) {
|
||||
key, err := secret()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
token, err := jwt.ParseWithClaims(tokenString, &Claims{}, func(token *jwt.Token) (any, error) {
|
||||
return key, nil
|
||||
},
|
||||
jwt.WithValidMethods([]string{jwt.SigningMethodHS256.Alg()}),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
claims, ok := token.Claims.(*Claims)
|
||||
if !ok || !token.Valid {
|
||||
return nil, errors.New("invalid token")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
const CtxUsernameKey = "username"
|
||||
|
||||
func Middleware() gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
h := c.GetHeader("Authorization")
|
||||
if h == "" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "missing Authorization header"})
|
||||
return
|
||||
}
|
||||
|
||||
const prefix = "Bearer "
|
||||
if !strings.HasPrefix(h, prefix) {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "expected Bearer token"})
|
||||
return
|
||||
}
|
||||
|
||||
raw := strings.TrimSpace(strings.TrimPrefix(h, prefix))
|
||||
if raw == "" {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "empty token"})
|
||||
return
|
||||
}
|
||||
|
||||
claims, err := ParseAccessToken(raw)
|
||||
if err != nil {
|
||||
c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "invalid token"})
|
||||
return
|
||||
}
|
||||
|
||||
c.Set(CtxUsernameKey, claims.Username)
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDjzCCAnegAwIBAgIUG1Qc10mXTy5+Zuh1COAK6fqAl34wDQYJKoZIhvcNAQEL
|
||||
BQAwVzELMAkGA1UEBhMCUlUxDzANBgNVBAgMBk1vc2NvdzERMA8GA1UEBwwIS29y
|
||||
b2x5b3YxEDAOBgNVBAoMB1NoYWdyYW0xEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0y
|
||||
NjAxMTQwMTMxNDhaFw0yNzAxMTQwMTMxNDhaMFcxCzAJBgNVBAYTAlJVMQ8wDQYD
|
||||
VQQIDAZNb3Njb3cxETAPBgNVBAcMCEtvcm9seW92MRAwDgYDVQQKDAdTaGFncmFt
|
||||
MRIwEAYDVQQDDAlsb2NhbGhvc3QwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQDLOB4WybryG6Cc4yU+2PPrLiM/tt15HMVp0TgcA277vofYFd90IArihbmG
|
||||
KEaKYyZplUzxk55RRNS6BaAroZb0AWEg8cOid83gbnuKKaIUhjz/CDADPnnRWynb
|
||||
PHjVuvIBtPLgyunbtB6U7a6JLP2nA8XaTcDFtLrhy8PTKFZ9fLRBXzxW8ZvNnL4i
|
||||
FSLQYe851dOfJ1m0HwA/meK8QWfYn01O8zprleSMo+HPIudRR6ySnx/Cy3LuAcqM
|
||||
sjttf6EFWs9XTiAOIbKC4M8VbOrfZjXFz45ljD0tZNziJ2g61lmdJAV8ElwZ6SDP
|
||||
fGTwGjWj5Qx9Lg7qdFqjVyE0QFBJAgMBAAGjUzBRMB0GA1UdDgQWBBSd7S5Xngb4
|
||||
9eeBbmTCslblkWClRDAfBgNVHSMEGDAWgBSd7S5Xngb49eeBbmTCslblkWClRDAP
|
||||
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA8Lx0PAhfYRuRYuQxV
|
||||
EyU4pmQ6JuAPl3gxVKHY6bFGMYooSRr5Nw/YulfPucxTKHtVlgY/l0kwofmTUh3B
|
||||
Df1tulFCCmBW4zbl6cHd7TVSEJBkV7R9AqAC49ni8mVhmo3uPuARFa+mR8ATrF4y
|
||||
LWlO/2n7F5g+093CqOG3b4O76PlqAl6L/z/Z+UBoMVEyiPgfxAztucsBn7oOaQwG
|
||||
g6ohX2kosC2uRsc1bAofHWW0u3tFY0i6oiI7XPF9REuWJOiDlN2PsDMXhSG5xeLj
|
||||
e7LUOQsNXB5deAfUFxbtEDCnEDzyp+GxXwZ0iPsJOzm2ccL6XdDzucCuR/NtuhGf
|
||||
KwpD
|
||||
-----END CERTIFICATE-----
|
||||
@@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDLOB4WybryG6Cc
|
||||
4yU+2PPrLiM/tt15HMVp0TgcA277vofYFd90IArihbmGKEaKYyZplUzxk55RRNS6
|
||||
BaAroZb0AWEg8cOid83gbnuKKaIUhjz/CDADPnnRWynbPHjVuvIBtPLgyunbtB6U
|
||||
7a6JLP2nA8XaTcDFtLrhy8PTKFZ9fLRBXzxW8ZvNnL4iFSLQYe851dOfJ1m0HwA/
|
||||
meK8QWfYn01O8zprleSMo+HPIudRR6ySnx/Cy3LuAcqMsjttf6EFWs9XTiAOIbKC
|
||||
4M8VbOrfZjXFz45ljD0tZNziJ2g61lmdJAV8ElwZ6SDPfGTwGjWj5Qx9Lg7qdFqj
|
||||
VyE0QFBJAgMBAAECggEALgf0UtOXd6M35omSBHIWkBknjVVRxc71TYKBS+EgOMA/
|
||||
23ua3Z4rcQN60k9ZqRuL1iMmJls6Y2yspcVD8lYcEAGm+1Qf7PNnrBRCgflrt+vv
|
||||
MZJsc7OpWrlkWf9Q3JLHogjXcgEsZyJdwfyzielpvDS/0nLFvVKyeRZTcUdEDhCz
|
||||
MoY3tqcZVwq1k+CsW5Z8C1DZaEwgwhEXNGPgfX7R86FSNwlNmcTKJG/YHb9xBA84
|
||||
O109pfe9PsQnYB9Lw+CNPHl1v6wIMRlVZZMFPevBJq+r9d8iN6dsX7c4oR8SXDDS
|
||||
4Shux9RNE8XyD6HOTK+QuEvJmZmPIFjnlVZIsVkpHQKBgQD5bfeh7En+VPdHFGTg
|
||||
+0o1ZSYrfvErak8zP7DoLZF4EY6CK20uZ8ou09ebWXZQfC37PliOSMJyDG70PuXc
|
||||
Rh/TfnUPkPbmyRrvQi+MAsIjCEYGk2iiMQvSVs099AB6oAQetyPm2AcT4HeGNaLM
|
||||
m1gurXTCelV0yT7oL7IhI6AqRQKBgQDQkoenTQ1nnvA4ghN253c+mbJWvTX+lbo9
|
||||
WicOAxmA9gp/VN7NErXbgr5FcMwPtT+yLDqDgSjLp2T9ClYt/laWcO/KYwrnP9o5
|
||||
DTeSB+biEAd3GHJLWJApY/dmFZey5uza+hXvlTdVCUgvFJYGgHw/Dg5E+jvUwrNT
|
||||
MNN/OnpQNQKBgAtxxz3vuIlp3pqtTd+gyAvhIzo1rd0fGJkyX+yXQqhurco9MdpC
|
||||
Ot2hLLBdD3er6vQvLSMCJaHT/jdIt4U+1nD+yWI4dYurSIgX0lSrP7sZwxTEKLXg
|
||||
aDlzcCFak7cMpoO+RXBvEwwPbYyD439d1VL29HeD423jWfaPUa4Bk3S9AoGAWGdj
|
||||
PBQ6tEr3wtvPaDyfnFcE8iLsueW4tLx7hULnEnQ26tWMQhvGHS6De2dd9uJ6Bwkc
|
||||
HBUot3lSIra45HHDPazM1lm4i1/THQ9vGGRlBjiJEX+5Ihp9sC2A9TH9xISArCgI
|
||||
GC6E73QptlrhZAwdnZRVlAMETR/hZkdxvaGJqmkCgYEAzHpqhLMFwOOvDr5Ya2DW
|
||||
5IGSCohsNBRvPKLSXlMIT1yMfRStsp5qQrZq2Oj2xXX7Jk3jf+1lU3ZQ5O6bI6br
|
||||
9MhrVKu6qI8YS3OtSDPAUOzPw1zu4yaKyCO0eNghY51PTZd3A3JA8Uh9Si7OCryD
|
||||
iHnkhUQ1iasZLdnubyVUuh0=
|
||||
-----END PRIVATE KEY-----
|
||||
+3
-3
@@ -23,12 +23,12 @@ function loadRooms() {
|
||||
function connectRoom() {
|
||||
const room = roomSelect.value || 'general';
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
|
||||
const host = window.location.host;
|
||||
if (ws) {
|
||||
ws.close();
|
||||
}
|
||||
|
||||
ws = new WebSocket(`${protocol}//localhost:8080/ws/${room}`);
|
||||
const wsUrl = `${protocol}//${host}/ws/${room}`;
|
||||
ws = new WebSocket(wsUrl);
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user