Skip to content

Commit

Permalink
chore: Update privacy API endpoint and add community creation API end…
Browse files Browse the repository at this point in the history
…point
  • Loading branch information
tako0614 committed Jul 7, 2024
1 parent 39c8922 commit 5666b56
Show file tree
Hide file tree
Showing 11 changed files with 546 additions and 43 deletions.
19 changes: 19 additions & 0 deletions models/communities.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import mongoose from "mongoose"

export const CommunitiesSchama = new mongoose.Schema({
uuid: {
type: String,
required: true,
unique: true,
},
name: {
type: String,
required: true,
},
description: {
type: String,
},
timestamp: { type: Date, default: Date.now },
})
const csrfToken = mongoose.model("communities", CommunitiesSchama)
export default csrfToken
13 changes: 5 additions & 8 deletions models/tempUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,9 @@ export const tempUsersSchema = new mongoose.Schema({
message: (props: { value: any }) => `${props.value} is not a valid mail address!`,
},
},
key: {
type: String,
required: true,
unique: true,
},
checkCode: {
type: Number,
required: true,
min: 0,
max: 4294967295,
},
checked: {
type: Boolean,
Expand All @@ -31,7 +24,11 @@ export const tempUsersSchema = new mongoose.Schema({
type: Number,
default: 0,
},
timestamp: { type: Date, default: Date.now },
token: {
type: String,
required: true,
},
timestamp: { type: Date, default: Date.now, expires: 60 * 60 * 24 },
})
const tempUsers = mongoose.model("tempUsers", tempUsersSchema)
export default tempUsers
7 changes: 6 additions & 1 deletion routes/api/v2/client/block/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import takos from "../../../../../util/takos.ts"
import { load } from "$std/dotenv/mod.ts"
import userConfig from "../../../../../models/userConfig.ts"
import users from "../../../../../models/users.ts"
import friends from "../../../../../models/friends.ts"
const env = await load()
export const handler = {
async POST(req: Request, ctx: any) {
Expand Down Expand Up @@ -55,14 +56,18 @@ export const handler = {
},
body: JSON.stringify({ userid: ctx.state.data.userid, blockedUser: userid, signature: new Uint8Array(signature) }),
})
if(remoteServer.status !== 200) {
if (remoteServer.status !== 200) {
return new Response(JSON.stringify({ status: false, message: "Failed to block user on remote server" }), {
headers: { "Content-Type": "application/json" },
status: 200,
})
}
}
//useridとfriendidが入っているfriendroomを削除
const roomtype = userDomain == env["DOMAIN"] ? "friend" : "remotefriend"
//友達リストから削除
await friends.updateOne({ userID: ctx.state.data.userid }, { $pull: { friends: { $in: [userid] } } })
await userConfig.updateOne({ userID: ctx.state.data.userid, types: roomtype }, { $pull: { friendRooms: { $in: [userid] } } })
return new Response(JSON.stringify({ status: true }), {
headers: { "Content-Type": "application/json" },
})
Expand Down
12 changes: 12 additions & 0 deletions routes/api/v2/client/create/community.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,15 @@
// POST /api/v2/client/create/community
// { name: string, description: string, csrftoken: string, icon: file }
// -> { status: boolean, message: string }
export const handler = {
async POST(req: Request, ctx: any) {
if (!ctx.state.data.loggedIn) {
return new Response(JSON.stringify({ status: "Please Login" }), {
headers: { "Content-Type": "application/json" },
status: 401,
})
}
const body = await req.json()
const { name, description, csrftoken, icon } = body
},
}
94 changes: 94 additions & 0 deletions routes/api/v2/client/sessions/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,97 @@
// POST /api/v2/client/sessions/login
// { email?: string, userName?: string, password: string}
// -> { status: boolean, message: string } cookie: sessionid=string; path=/; max-age=number; httpOnly; SameSite=Strict;
import users from "../../../../../models/users.ts"
import sessionID from "../../../../../models/sessionid.ts"
export const handler = {
async POST(req: Request, ctx: any) {
if (ctx.state.data.loggedIn) {
return new Response(JSON.stringify({ status: "Already Logged In" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
const body = await req.json()
const { email, userName, password } = body
if (typeof password !== "string") {
return new Response(JSON.stringify({ status: false, message: "Invalid password" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (typeof email !== "string" && typeof userName !== "string") {
return new Response(JSON.stringify({ status: false, message: "Invalid email or userName" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
//emailでログイン
let user
if (typeof email === "string") {
user = await users.findOne({ email: email })
if (user === null) {
return new Response(JSON.stringify({ status: false, message: "User not found" }), {
headers: { "Content-Type": "application/json" },
status: 404,
})
}
}
//userNameでログイン
if (typeof userName === "string") {
user = await users.findOne({ userName: userName })
if (user === null) {
return new Response(JSON.stringify({ status: false, message: "User not found" }), {
headers: { "Content-Type": "application/json" },
status: 404,
})
}
}
if (user === null || user === undefined) {
return new Response(JSON.stringify({ status: false, message: "User not found" }), {
headers: { "Content-Type": "application/json" },
status: 404,
})
}
const salt = user.salt
const hash = user.password
const saltPassword = password + salt
const reqHash = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(saltPassword),
)
const hashArray = new Uint8Array(reqHash)
const hashHex = Array.from(
hashArray,
(byte) => byte.toString(16).padStart(2, "0"),
).join("")
if (hash !== hashHex) {
return new Response(
JSON.stringify({ "status": false, error: "password" }),
{
headers: { "Content-Type": "application/json" },
status: 403,
},
)
}
const sessionIDarray = new Uint8Array(64)
const randomarray = crypto.getRandomValues(sessionIDarray)
const sessionid = Array.from(
randomarray,
(byte) => byte.toString(16).padStart(2, "0"),
).join("")
const result = await sessionID.create({
userid: user.uuid,
sessionID: sessionid,
})

if (result !== null) {
return new Response(JSON.stringify({ "status": true }), {
headers: {
"Content-Type": "application/json",
"Set-Cookie": `sessionid=${sessionid}; Path=/; Max-Age=2592000;`,
},
status: 200,
})
}
},
}
29 changes: 29 additions & 0 deletions routes/api/v2/client/sessions/logout.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,32 @@
//sessionidを削除してcookieを削除する
// POST /api/v2/client/sessions/logout
// { csrftoken: string }
// -> { status: boolean, message: string }
import sessionID from "../../../../../models/sessionid.ts"
import takos from "../../../../../util/takos.ts"
export const handler = {
async POST(req: Request, ctx: any) {
if (!ctx.state.data.loggedIn) {
return new Response(JSON.stringify({ status: "Already Logged Out" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
const body = await req.json()
if (await takos.checkCsrfToken(body.csrftoken) === false) {
return new Response(JSON.stringify({ status: false, message: "Invalid CSRF token" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
await sessionID.deleteOne({ sessionID: ctx.state.data.sessionID })
//cookieを削除するheaderを返す
return new Response(JSON.stringify({ status: true, message: "Logged Out" }), {
headers: {
"Content-Type": "application/json",
"Set-Cookie": `sessionid=; path=/; max-age=0; httpOnly; SameSite=Strict;`,
},
status: 200,
})
},
}
140 changes: 139 additions & 1 deletion routes/api/v2/client/sessions/registers/auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,142 @@
//本登録するapi
//POST /api/v2/client/sessions/registers/auth
// { email: string, password: string, nickName: string,age: string, token: string, recaptcha: string }
// { email: string, password: string, nickName: string,age: string, token: string, recaptcha: string, userName: string}
// -> { status: boolean, message: string }
import { load } from "$std/dotenv/mod.ts"
import tempUsers from "../../../../../../models/tempUsers.ts"
import users from "../../../../../../models/users.ts"
import takos from "../../../../../../util/takos.ts"
const env = await load()
export const handler = {
async POST(req: Request, ctx: any) {
if (ctx.state.data.loggedIn) {
return new Response(JSON.stringify({ status: "Already Logged In" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
const body = await req.json()
const { email, password, nickName, age, token, recaptcha, userName } = body
if (takos.checkEmail(email) === false) {
return new Response(JSON.stringify({ status: false, message: "Invalid email" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (takos.checkUserName(userName) === false) {
return new Response(JSON.stringify({ status: false, message: "Invalid userName" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (takos.checkNickName(nickName) === false) {
return new Response(JSON.stringify({ status: false, message: "Invalid nickName" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (takos.checkAge(age) === false) {
return new Response(JSON.stringify({ status: false, message: "Invalid age" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (takos.checkPassword(password) === false) {
return new Response(JSON.stringify({ status: false, message: "Invalid password" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (typeof token !== "string") {
return new Response(JSON.stringify({ status: false, message: "Invalid token" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
const isSecsusRechapcha = await fetch(
`https://www.google.com/recaptcha/api/siteverify?secret=${Deno.env.get("RECAPTCHA_SECRET_KEY")}&response=${recaptcha}`,
)
const score = await isSecsusRechapcha.json()
if (score.score < 0.5 || score.success == false) {
console.log(score)
return new Response(
JSON.stringify({ "status": false, error: "rechapcha" }),
{
headers: { "Content-Type": "application/json" },
status: 403,
},
)
}
const tempUser = await tempUsers.findOne({
email: email,
token: token,
})
if (tempUser === null) {
return new Response(JSON.stringify({ status: false, message: "Invalid token" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
if (tempUser.checked) {
return new Response(JSON.stringify({ status: false, message: "Already Registered" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
const user = await users.findOne({
email: email,
})
if (user !== null) {
return new Response(JSON.stringify({ status: false, message: "Already Registered" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
//ユーザー名がかぶっていないか確認
const userNameUser = await users.findOne({
userName: userName,
})
if (userNameUser !== null) {
return new Response(JSON.stringify({ status: false, message: "Already Registered" }), {
headers: { "Content-Type": "application/json" },
status: 400,
})
}
//本登録
await tempUsers.deleteOne({
email: email,
})
//塩を生成
const array = new Uint8Array(32)
crypto.getRandomValues(array)
const salt = Array.from(
array,
(byte) => byte.toString(16).padStart(2, "0"),
).join("")
//パスワードをハッシュ化
const saltPassword = password + salt
const hash = await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(saltPassword),
)
const hashArray = new Uint8Array(hash)
const hashHex = Array.from(
hashArray,
(byte) => byte.toString(16).padStart(2, "0"),
).join("")
//ユーザーを登録
const uuid = crypto.randomUUID() + "@" + env["serverDomain"]
await users.create({
uuid: uuid,
userName,
nickName,
mail: email,
password: hashHex,
salt: salt,
age: age,
})
return new Response(JSON.stringify({ status: true }), {
headers: { "Content-Type": "application/json" },
})
},
}
Loading

0 comments on commit 5666b56

Please sign in to comment.