👉🏻 myapp53에서는 부스트와 좋아요 부분 보안을 강화합니다.
myapp53 is strengthening security for the Boost and Like features.
👉🏻 로그인 하지 않으면 부스트나 좋아요를 클릭하면 로그인화면으로 이동합니다.
If you are not logged in, clicking “Boost” or “Like” will redirect you to the login screen.
👉🏻 사용하지않는 getToken함수를 삭제합니다.
Remove the unused getToken function.
👉🏻 로컬 서버에서 글 작성할 때 첨부 파일이 있는 경우 첨부파일 리스트가 초기화 되지 않는 문제를 수정합니다.
Fixes an issue where the attachment list was not reset when creating a post with attachments on a local server.
👉🏻 전체 코드는 깃허브에서 확인 할 수 있습니다.
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(deprecated)
│ ├── api/timeline/route.ts -> Timeline API
│ ├── api/followinglist/route.ts -> followinglist API
│ ├── api/followerslist/route.ts -> followerslist API
│ ├── api/v1/instance/route.ts -> auth
│ ├── api/v1/apps/route.ts. -> auth
│ ├── api/v1/accounts/verify_credentials/route.ts -> auth
│ ├── api/v1/statuses/route.ts -> Write Post
│ ├── api/v1/timelines/home/route.ts -> timeline
│ ├── api/v1/media/route.ts -> Image upload
│ ├── api/v1/media/[id]/route.ts -> Image Delete
│ ├── oauth/authorize/route.ts -> auth
│ ├── oauth/token/route.ts -> auth
│ ├── api/v1/search/home/route.ts -> search
│ ├── api/v2/search/home/route.ts -> search
│ ├── api/v1/accounts/[id]/followers/route.ts -> followers
│ ├── api/v1/accounts/[id]/following/route.ts -> following
│ ├── api/v1/statuses/[id]/route.ts -> -> Post delete(pinafore)
│ ├── api/auth/signup/route.ts -> Signup
│ ├── api/auth/login/route.ts -> Login
│ ├── api/auth/logout/route.ts -> Logout
│ ├── api/auth/refresh/route.ts -> Refresh Token
│ ├── api/cleanup-orphan/route.ts -> post,outbox clean up
│ ├── api/auth/me/route.tsx -> Login Check
│ ├── auth/signup/page.tsx -> Signup UI
│ ├── auth/signup/page.tsx -> Login UI
│ ├── 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(Server, 404)
│ │ ├── ClientPage.tsx. -> Timeline UI(Client,Call Active Themes)
│ │ └── _components/themes/
│ │ ├── themeex/ThemeexTheme.tsx -> Example Theme
│ │ ├── pinafore/PinaforeTheme.tsx -> Theme 1
│ │ ├── pinafore/FollowersList.tsx -> Theme 1, FollowersList
│ │ ├── pinafore/FollowingList.tsx -> Theme 1, FollowingList
│ │ ├── pinafore/NotificationsList.tsx -> Theme 1, NotificationsList
│ │ ├── 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
│ ├── visibility.ts -> Visibility(Public,Unlisted,Private,Direct)
│ └── 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
📁 프로젝트 시작 / Project Start
📁 코드수정 / Code Modification
✔️ 버그 수정 / Bug fixes
— 글 작성 후 이미지 첨부 리스트와 프리뷰를 초기화 합니다.
After posting, the list of attached images and the preview are reset.
A.app/usersui/[username]/_components/themes/pinafore/PinaforeTheme.tsx
const handlePost = async () => {
if (!composeText.trim() || posting) return;
setPosting(true);
try {
// 토큰 있으면 헤더에 넣고 없으면 쿠키 인증으로
// Include the token in the header if present; otherwise, use cookie authentication.
const token = localStorage.getItem('access_token') || localStorage.getItem('token') || '';
const res = await fetch('/api/v1/statuses', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(token? { Authorization: `Bearer ${token}` } : {})
},
credentials: 'include',
body: JSON.stringify({
status: composeText,
visibility: composeVis,
media_ids: mediaIds // ✅ myapp51 - add media_ids
})
});
if (res.ok) {
const newPost = await res.json();
setComposeText('');
setMediaIds([]); // ✅ myapp53 - 첨부 리스트 초기화 / Reset attachment list
setPreviews([]); // ✅ myapp53 - 프리뷰 초기화 / Reset Preview
// 타임라인 맨 위에 즉시 추가 / Add immediately to the top of the timeline
setTimeline((prev: any[]) => [{
id: newPost.id, content: newPost.content, actor: `https://${DOMAIN}/users/${username}`,
username: username,
created_at: new Date().toISOString(),
source: 'local',
isMine: true,
visibility: composeVis,
media_attachments: newPost.media_attachments || [] // ✅ myap51 - preview
},...prev]);
setCounts(c => ({...c, posts: c.posts + 1}));
} else alert('게시 실패');
} catch (e) { console.error(e); alert('게시 실패'); }
setPosting(false);
};
✔️ 부스트 보안강화 / Boost Security Enhancement
— 로그인하지 않으면 부스트 기능을 사용할 수 없도록 합니다.
Disable the use of the boost function if the user is not logged in.
A.app/api/announce/route.ts – 백엔드 / Backend
... ...
function getUser(req: Request) {
const auth = req.headers.get('Authorization')?.replace('Bearer ','').trim();
if (auth) {
const o = db.prepare('SELECT username FROM oauth_tokens WHERE access_token=?').get(auth) as any;
if (o?.username) return o.username;
}
const cookie = req.headers.get('cookie') || '';
const m = cookie.match(/refresh_token=([^;]+)/);
if (m) {
const s = db.prepare('SELECT username FROM sessions WHERE refresh_token=?').get(m[1]) as any;
if (s?.username) return s.username;
}
return null;
}
export async function POST(req: NextRequest) {
try {
//const { username, target } = await req.json();
const authUser = getUser(req);
if (!authUser) {
return NextResponse.json({ error: '로그인 필요 / authentication required' }, { status: 401 });
}
const { target } = await req.json();
const username = authUser;
... ...
}
export async function DELETE(req: NextRequest) {
try {
// ✅ myapp53 - 부스트 삭제 보안강화 / Boost Removal & Security Enhancement
//const { username, target } = await req.json();
const authUser = getUser(req);
if (!authUser) {
return NextResponse.json({ error: '로그인 필요/ authentication required' }, { status: 401 });
}
const { target } = await req.json();
const username = authUser;
... ...
}
B.app/usersui/[username]/_components/themes/pinafore/PinaforeTheme.tsx – 프론트엔드 / Frontend
a.부스트 보안강화 / Boost Security Enhancement
... ...
// ✅ myapp53-boost-secure: 부스트 보안강화 Boost Security Enhancement
const handleBoostClick = async (p: any) => {
if (!currentUser) return window.location.href = `/auth/login?next=/@${username}`;
onBoost(p)
};
// ✅ myapp53-boost-secure: 좋아요 보안강화 / Like Security Enhancement
const handleLikeClick = (p: any) => {
if (!currentUser) return window.location.href = `/auth/login?next=/@${username}`;
onLike(p);
};
... ...
b.버그수정(사용하지 않는 getToken함수 부분) / Bug fix (unused getToken function)
... ...
// ✅ deprecated(myapp53)-myapp51 - 토큰가져오가 , url 경로보정 / Retrieve token, adjust URL path
// ✅ myapp53 - 토큰 제거, 쿠키 인증만 사용 / cookie auth only
//const getToken = () => localStorage.getItem('access_token') || localStorage.getItem('token') || '';
... ...
// ✅ myapp53 - cookie auth only
//const token = localStorage.getItem('access_token') || localStorage.getItem('token') || '';
const handleDelete = async (postId: string) => {
... ...
const res = await fetch(`/api/v1/statuses/${postId}`, {
method: 'DELETE',
// headers: {
// ...(token? { Authorization: `Bearer ${token}` } : {})
// },
credentials: 'include' // refresh_token 쿠키 포함 / Include refresh_token cookie
});
... ...
}
... ...
const handlePost = async () => {
... ...
// ✅ myapp53 - cookie auth only
const res = await fetch('/api/v1/statuses', {
method: 'POST',
// headers: {
// 'Content-Type': 'application/json',
// ...(token? { Authorization: `Bearer ${token}` } : {})
// },
credentials: 'include',
body: JSON.stringify({
status: composeText,
visibility: composeVis,
media_ids: mediaIds // ✅ myapp51 - add media_ids
})
});
... ...
if (res.ok) {
const newPost = await res.json();
setComposeText('');
setMediaIds([]); // ✅ myapp53 - 첨부 리스트 초기화 / Reset attachment list
setPreviews([]); // ✅ myapp53 - 프리뷰 초기화 / Reset Preview
... ...
}
... ...
}
async function onFiles(e: React.ChangeEvent<HTMLInputElement>) {
// ✅ myapp53 - Cookie auth only
//const token = getToken();
... ...
const res = await fetch('/api/v1/media', {
method: 'POST',
body: fd,
//headers: {...(token? { Authorization: `Bearer ${token}` } : {}) },// ✅ myapp53 - Cookie auth only
credentials: 'include'
});
... ...
}
✔️ 좋아요 보안강화 / Like Security Enhancement
— 로그인하지 않으면 좋아요 기능을 사용할 수 없도록 합니다.
Disable the ‘like’ function for users who are not logged in.
A.app/api/announce/route.ts – 백엔드 / Backend
... ...
function getUser(req: Request) {
const auth = req.headers.get('Authorization')?.replace('Bearer ','').trim();
if (auth) {
const o = db.prepare('SELECT username FROM oauth_tokens WHERE access_token=?').get(auth) as any;
if (o?.username) return o.username;
}
const cookie = req.headers.get('cookie') || '';
const m = cookie.match(/refresh_token=([^;]+)/);
if (m) {
const s = db.prepare('SELECT username FROM sessions WHERE refresh_token=?').get(m[1]) as any;
if (s?.username) return s.username;
}
return null;
}
export async function POST(req: NextRequest) {
//const { username, target } = await req.json();
// ✅ myapp53 - 좋아요 보안강화 / like Security Enhancement
//const { username, target } = await req.json();
const authUser = getUser(req);
if (!authUser) {
return NextResponse.json({ error: '로그인 필요 / authentication required' }, { status: 401 });
}
const { target } = await req.json();
const username = authUser;
... ...
}
export async function DELETE(req: NextRequest) {
// ✅ myapp53 - 좋아요 보안강화 / like Security Enhancement
//const { username, target } = await req.json();
const authUser = getUser(req);
if (!authUser) {
return NextResponse.json({ error: '로그인 필요 / authentication required' }, { status: 401 });
}
const { target } = await req.json();
const username = authUser;
... ...
}
B.app/usersui/[username]/_components/themes/pinafore/PinaforeTheme.tsx – 프론트엔드 / Frontend
— 위의 부스트 보안강화 부분의 코드를 참조하세요
Please refer to the code in the Boost security enhancement section above.
📁 테스트 / Test
✔️ 첨부파일 리스트 초기화 테스트
Attachment list reset test

✔️ 로그아웃시 좋아요,부스트 클릭하면 로그인 페이지로 이동
If you click “Like” or “Boost” while logged out, you will be redirected to the login page.

✔️ 로그인시 좋아요,부스트 작동확인
Verify that ‘Like’ and ‘Boost’ functions work upon login.
— Local Server

— GTS Server

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