👉🏻 회원가입 및 로그인 기능을 시작합니다.
We are launching the sign-up and login functions.
👉🏻 publick key 검증로직을 추가했습니다.(기존은 검증 없이 패스)
Added public key verification logic (previously, it proceeded without verification).
👉🏻 User테이블 구조를 변경 했습니다.
The User table structure has been modified.
👉🏻 전체 코드는 깃허브에서 확인 할 수 있습니다.
You can find the full code on GitHub.
https://github.com/gideonslife01/flm-nextjs
📁 전체 프로젝트 구조 / Overall Project Structure
myapp project/
├── app/ (Next.js App Router)
│ ├── .well-known/webfinger/route.ts -> webfinger
│ ├── api/follow/route.ts -> Follow API(temporary)
│ ├── api/announce/route.ts -> Boost(Announcement)
│ ├── api/like/route.ts. -> Like API
│ ├── api/posts/route.ts -> Writing API
│ ├── api/timeline/route.ts -> Timeline API
│ ├── users/[username]/
│ │ ├── statuses/[id]/route.ts -> Indivisual Post
│ │ ├── route.ts -> Acotr Information
│ │ ├── followers/route.ts -> Followers List
│ │ ├── following/route.ts -> Following List
│ │ ├── inbox/route.ts -> Inbox
│ │ └── outbox/route.ts -> outbox
│ ├── usersui/[username]/
│ │ ├── page.tsx -> Timeline UI
│ │ └── _components/themes/
│ │ ├── themeex/ThemeexTheme.tsx -> Example Theme
│ │ ├── pinafore/PinaforeTheme.tsx -> Theme 1
│ │ ├── mastodon/MastodonTheme.tsx -> Theme 2
│ │ └── minimal/MinimaltTheme.tsx -> Theme 3
│ ├── layout.tsx, page.tsx, globals.css
│ └── favicon.ico
├── lib/
│ ├── theme.tsx -> Theme Provider
│ ├── watchThemes.ts -> Check real-time theme changes
│ ├── auth.ts -> Authentication, User Management
│ ├── ap.ts -> Follow,Undo,Create,Likes,Announce
│ └── db.ts -> DB connection
├── data/
│ ├── keys/userIDs/ -> private.pem, public.pem(New)
│ └── keys/ -> private.pem, public.pem(legacy)
├── data.sqlite -> Database(1/3)
├── data.sqlite-wal -> Database(2/3)
├── data.sqlite-shm -> Database(3/3)
├── Caddyfile -> https
├── instrumentation.ts -> Background Server
└── package.json
📁 프로젝트 시작
📁 모듈 설치 / Module install
— 비밀번호 암호화 / Password encryption
npm install bcrypt jsonwebtoken
npm install -D @types/bcrypt @types/jsonwebtoken
📁 DB 마이그레이션 / DB Migration
✔️ 기존 Users테이블에서 User1을 유지하고 정보를 업데이트합니다.
Retain User1 in the existing Users table and update its information.
✔️ Users 테이블 / User Table
— email,password_hash,email_verified,vaerification_token 필드를 추가합니다.
Add the email, password_hash, email_verified, and verification_token fields.
CREATE TABLE users (
username TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
summary TEXT DEFAULT '',
private_key TEXT,
public_key TEXT,
email TEXT UNIQUE,
password_hash TEXT,
email_verified INTEGER DEFAULT 0,
verification_token TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
✔️ SQLITE
— ALTER명령어로는 UNIQUE를 추가할 수 없어서 테이블을 새로만듭니다.
Since a UNIQUE constraint cannot be added using the ALTER command, I am creating a new table.
# - 테이블 신규 생성 / Create New Table -
sqlite3 data.sqlite
# - 기존 테이블 삭제(UNIQUE는 ALTER로 입력 불가능) -
# Delete existing table (UNIQUE constraint cannot be added via ALTER)
DROP TABLE IF EXISTS users;
# - 테이블 생성 / Create Table --
CREATE TABLE users (
username TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
summary TEXT DEFAULT '',
private_key TEXT,
public_key TEXT,
email TEXT UNIQUE,
password_hash TEXT,
email_verified INTEGER DEFAULT 0,
verification_token TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
);
# - 사용자 입력(패스워드 1111) --
# User input (password 1111
INSERT INTO users (username, display_name, summary, email, password_hash, email_verified)
VALUES ('user1','user1','My Fediverse account on aloy-horizon','freelifemakers@gmail.com','$2b$10$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW',1);
SELECT * FROM users;
— Private ,Public 키 생성 및 DB업데이트(또는 기존 키 활용)
Generate private and public keys and update the database (or utilize existing keys)
# 키 생성 / Key Generation
cd ~/myapp31
node -e "
const crypto = require('crypto');
const fs = require('fs');
const { privateKey, publicKey } = crypto.generateKeyPairSync('rsa', {
modulusLength: 2048,
publicKeyEncoding: {type: 'spki', format: 'pem'},
privateKeyEncoding: {type: 'pkcs8', format: 'pem'}
});
fs.writeFileSync('pri.pem', privateKey);
fs.writeFileSync('pub.pem', publicKey);
console.log('생성됨!');
console.log('private length:', privateKey.length);
console.log('public length:', publicKey.length);
"
# cat 명령어로 키 확인후 DB에 업데이트 하기
Check the key using the `cat` command and update the database.
# DB Update / DB Update
UPDATE users SET
private_key = '-----BEGIN PRIVATE KEY-----',
public_key = '-----BEGIN PUBLIC KEY-----'
WHERE username = 'user1';
SELECT username, length(private_key) as pri_len, length(public_key) as pub_len FROM users;
— 사용자 디렉토리 만들고 키 파일 복사(db.ts로직이랑 맞추기 위해서)
Create the user directory and copy the key file (to align with the db.ts logic).
# 기존파일유지
# Keep existing files
# /myapp31/data/keys/
user1 % ls
private.pem public.pem
# 신규파일
# New File
#/myapp31/data/keys/user1
user1 % ls
private.pem public.pem
1) 회원가입시 키는 data/keys/userid/private_key.pem or public_key.pem 으로 저장 됨.
📁 코드추가 / Add code
✔️ 회원가입처리나 로그인관련 함수입니다.
These are functions related to user registration and login processing.
— lib/auth.ts
... ...
export async function hashPassword(password: string) {
... ...
}
export async function verifyPassword(password: string, hash: string) {
... ...
}
export function createToken(username: string) {
... ...
}
export function verifyToken(token: string) {
... ...
}
export function getUser(username: string) {
... ...
}
export function getUserByEmail(email: string) {
... ...
}
// ✅ myapp31 - 신규 유저 생성 (키도 같이 생성!) / Create a new user (with keys!)
export function createUser(username: string, email: string, passwordHash: string, displayName: string = '') {
... ...
}
// ✅ myapp31 -기존 DB -> 파일로 마이그레이션! / Migrate existing DB keys to files!
export function migrateKeysToFiles() {
... ...
}
... ...
📁 코드 수정 / Code Modification
✔️ lib/db.ts
// lib/db.ts
// keys 폴더 생성! / Create keys folder!
const keysDir = path.join(process.cwd(), 'data/keys');
if (!fs.existsSync(keysDir)) {
fs.mkdirSync(keysDir, { recursive: true });
console.log('✅ keys 폴더 생성/ keys folder created:', keysDir);
}
... ...
db.exec(`
CREATE TABLE IF NOT EXISTS users (
username TEXT PRIMARY KEY,
display_name TEXT DEFAULT '',
summary TEXT DEFAULT '',
private_key TEXT,
public_key TEXT,
email TEXT UNIQUE,
password_hash TEXT,
email_verified INTEGER DEFAULT 0,
verification_token TEXT,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP);
`);
✔️ publick key 검증로직 부분 수정
Modified the public key verification logic.
— lib/ap.ts
1) Publick Key 검증로직 추가
Added public key verification logic.
2)getPublicKey, verifyHttpSignature, fetchActorPublicKey 함수 추가
Added getPublicKey, verifyHttpSignature, and fetchActorPublicKey functions.
function getPublicKey(username: string): string {
... ...
}
... ...
export async function verifyHttpSignature(
req: Request,
publicKeyPem: string
): Promise<boolean> { ... ...}
export async function fetchActorPublicKey(actorUrl: string): Promise<string> { ... ...
}
✔️ 내 서버로 팔로우 요청시 Public Key로 검증
Verify using the public key when a follow request is sent to my server.
— app/api/inbox/route.ts
export async function POST(req: Request, { params }: { params: Promise<{ username: string }> }) {
const { username } = await params;
let body: any;
let rawBody = '';
try {
// rawBody를 먼저 읽기 / Read rawBody first
rawBody = await req.text();
try {
body = JSON.parse(rawBody);
} catch {
console.log('⚠️ JSON 파싱 실패! 빈 바디? / Failed to parse JSON! Empty body?', rawBody.slice(0,200));
return new Response('', { status: 202 });
}
// const body = await req.json();
console.log(`📩 [${username}] INBOX:`, body.type, body.actor, body.id);
... ...
}
... ...
}
1) 팔로우,언팔로우,글 받기,좋아요,부스트 모두 publick key로 검증
Follow, undo, receive posts, like, and boost(announce) actions are all verified using public keys.
📁 테스트 / Test
✔️ 마스토돈 서버에서 aloy-horizon-duckdns.org를 언팔로우하고 다시 팔로우 하기

✔️ 키 검증 로그 확인하기 / Checking Key Verification Logs

요한복음 8장 32절 / John 8:32
“그리고 너희는 진리를 알게 될 것이며, 진리가 너희를 자유롭게 할 것이다.”
“Then you will know the truth ,and the truth will set you free”