Progress so far
This commit is contained in:
75
app/api/account/authorize/route.ts
Normal file
75
app/api/account/authorize/route.ts
Normal file
@ -0,0 +1,75 @@
|
||||
import axios from 'axios'
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
const code = searchParams.get('code') as string
|
||||
const scope = searchParams.get('scope') as string
|
||||
const state = searchParams.get('state') as string
|
||||
|
||||
console.log("CODE:", code)
|
||||
console.log("SCOPE:", scope)
|
||||
console.log("STATE:", state)
|
||||
if (!code || !scope || !state) {
|
||||
return new NextResponse("Bad Request", { status: 400 });
|
||||
}
|
||||
console.log("VERIFY")
|
||||
// Verify state against user id in user table.
|
||||
const user = await db.user.findFirst({
|
||||
where: {
|
||||
id: state
|
||||
}
|
||||
})
|
||||
|
||||
console.log("USER", user)
|
||||
if (!user) {
|
||||
return new NextResponse("Bad Request", { status: 400 });
|
||||
}
|
||||
|
||||
console.log("FETCH TOKEN")
|
||||
// Post to https://id.twitch.tv/oauth2/token
|
||||
const token: { access_token:string, expires_in:number, refresh_token:string, token_type:string, scope:string[] } = (await axios.post("https://id.twitch.tv/oauth2/token", {
|
||||
client_id: process.env.TWITCH_BOT_CLIENT_ID,
|
||||
client_secret: process.env.TWITCH_BOT_CLIENT_SECRET,
|
||||
code: code,
|
||||
grant_type: "authorization_code",
|
||||
redirect_uri: "https://hermes.goblincaves.com/api/account/authorize"
|
||||
})).data
|
||||
console.log("TOKEN", token)
|
||||
|
||||
// Fetch values from token.
|
||||
const { access_token, expires_in, refresh_token, token_type } = token
|
||||
console.log("AT", access_token)
|
||||
console.log("RT", refresh_token)
|
||||
console.log("TT", token_type)
|
||||
|
||||
if (!access_token || !refresh_token || token_type !== "bearer") {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
let info = await axios.get("https://api.twitch.tv/helix/users?login=" + user.username, {
|
||||
headers: {
|
||||
"Authorization": "Bearer " + access_token,
|
||||
"Client-Id": process.env.TWITCH_BOT_CLIENT_ID
|
||||
}
|
||||
})
|
||||
console.log(info.data.data)
|
||||
const broadcasterId = info.data.data[0]['id']
|
||||
|
||||
await db.twitchConnection.create({
|
||||
data: {
|
||||
broadcasterId: broadcasterId,
|
||||
accessToken: access_token,
|
||||
refreshToken: refresh_token,
|
||||
userId: state
|
||||
}
|
||||
})
|
||||
|
||||
return new NextResponse("", { status: 200 });
|
||||
} catch (error) {
|
||||
console.log("[ACCOUNT]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
73
app/api/account/reauthorize/route.ts
Normal file
73
app/api/account/reauthorize/route.ts
Normal file
@ -0,0 +1,73 @@
|
||||
import axios from 'axios'
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
import { GET as authorize } from '../authorize/route'
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
// Verify state against user id in user table.
|
||||
const key = await db.apiKey.findFirst({
|
||||
where: {
|
||||
id: req.headers.get('x-api-key') as string
|
||||
}
|
||||
})
|
||||
|
||||
console.log("API USER:", key)
|
||||
if (!key) {
|
||||
return new NextResponse("Forbidden", { status: 403 });
|
||||
}
|
||||
|
||||
const connection = await db.twitchConnection.findFirst({
|
||||
where: {
|
||||
userId: key.userId
|
||||
}
|
||||
})
|
||||
if (!connection) {
|
||||
return new NextResponse("Forbidden", { status: 403 });
|
||||
}
|
||||
|
||||
try {
|
||||
const { expires_in }: { client_id:string, login:string, scopes:string[], user_id:string, expires_in:number } = (await axios.get("https://id.twitch.tv/oauth2/validate", {
|
||||
headers: {
|
||||
Authorization: 'OAuth ' + connection.accessToken
|
||||
}
|
||||
})).data;
|
||||
if (expires_in > 3600)
|
||||
return new NextResponse("", { status: 201 });
|
||||
} catch (error) {
|
||||
console.log("Oudated Twitch token.")
|
||||
}
|
||||
|
||||
// Post to https://id.twitch.tv/oauth2/token
|
||||
const token: { access_token:string, expires_in:number, refresh_token:string, token_type:string, scope:string[] } = (await axios.post("https://id.twitch.tv/oauth2/token", {
|
||||
client_id: process.env.TWITCH_BOT_CLIENT_ID,
|
||||
client_secret: process.env.TWITCH_BOT_CLIENT_SECRET,
|
||||
grant_type: "refresh_token",
|
||||
refresh_token: connection.refreshToken
|
||||
})).data
|
||||
|
||||
// Fetch values from token.
|
||||
const { access_token, expires_in, refresh_token, token_type } = token
|
||||
console.log("AT", access_token)
|
||||
console.log("RT", refresh_token)
|
||||
console.log("TT", token_type)
|
||||
|
||||
if (!access_token || !refresh_token || token_type !== "bearer") {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
await db.twitchConnection.update({
|
||||
where: {
|
||||
userId: key.userId
|
||||
},
|
||||
data: {
|
||||
accessToken: access_token
|
||||
}
|
||||
})
|
||||
|
||||
return new NextResponse("", { status: 200 });
|
||||
} catch (error) {
|
||||
console.log("[ACCOUNT]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
67
app/api/account/route.ts
Normal file
67
app/api/account/route.ts
Normal file
@ -0,0 +1,67 @@
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { generateToken } from "../token/route";
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
return NextResponse.json(await fetchUserUsingAPI(req))
|
||||
} catch (error) {
|
||||
console.log("[ACCOUNT]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const session = await getServerSession()
|
||||
const user = session?.user?.name
|
||||
if (!user) {
|
||||
return new NextResponse("Internal Error", { status: 401 })
|
||||
}
|
||||
|
||||
const exist = await db.user.findFirst({
|
||||
where: {
|
||||
username: user.toLowerCase() as string
|
||||
}
|
||||
});
|
||||
|
||||
if (exist) {
|
||||
// const apikey = await db.apiKey.findFirst({
|
||||
// where: {
|
||||
// userId: user.toLowerCase() as string
|
||||
// }
|
||||
// })
|
||||
return {
|
||||
id: exist.id,
|
||||
username: exist.username,
|
||||
//key: apikey?.id as string
|
||||
};
|
||||
}
|
||||
|
||||
const newUser = await db.user.create({
|
||||
data: {
|
||||
username: user.toLowerCase() as string,
|
||||
}
|
||||
});
|
||||
|
||||
// const apikey = await db.apiKey.create({
|
||||
// data: {
|
||||
// id: generateToken(),
|
||||
// label: "Default",
|
||||
// userId: user.toLowerCase() as string
|
||||
// }
|
||||
// })
|
||||
|
||||
return NextResponse.json({
|
||||
id: newUser.id,
|
||||
username: newUser.username,
|
||||
//key: apikey.id
|
||||
});
|
||||
} catch (error) {
|
||||
console.log("[ACCOUNT]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
40
app/api/auth/[...nextauth]/options.ts
Normal file
40
app/api/auth/[...nextauth]/options.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import type { NextAuthOptions } from "next-auth";
|
||||
import TwitchProvider from "next-auth/providers/twitch";
|
||||
|
||||
export interface TwitchProfile extends Record<string, any> {
|
||||
sub: string
|
||||
preferred_username: string
|
||||
email: string
|
||||
picture: string
|
||||
}
|
||||
|
||||
export const options: NextAuthOptions = {
|
||||
providers: [
|
||||
TwitchProvider({
|
||||
clientId: process.env.TWITCH_CLIENT_ID as string,
|
||||
clientSecret: process.env.TWITCH_CLIENT_SECRET as string,
|
||||
authorization: {
|
||||
params: {
|
||||
scope: "openid user:read:email",
|
||||
claims: {
|
||||
id_token: {
|
||||
email: null,
|
||||
picture: null,
|
||||
preferred_username: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
idToken: true,
|
||||
profile(profile) {
|
||||
return {
|
||||
id: profile.sub,
|
||||
name: profile.preferred_username,
|
||||
email: profile.email,
|
||||
image: profile.picture,
|
||||
}
|
||||
},
|
||||
})
|
||||
],
|
||||
secret: process.env.NEXTAUTH_SECRET
|
||||
}
|
6
app/api/auth/[...nextauth]/route.ts
Normal file
6
app/api/auth/[...nextauth]/route.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import NextAuth from 'next-auth'
|
||||
import { options } from './options'
|
||||
|
||||
const handler = NextAuth(options)
|
||||
|
||||
export { handler as GET, handler as POST }
|
23
app/api/settings/connections/twitch/delete/route.ts
Normal file
23
app/api/settings/connections/twitch/delete/route.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { db } from "@/lib/db"
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const user = await fetchUserUsingAPI(req)
|
||||
if (!user) {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const connection = await db.twitchConnection.deleteMany({
|
||||
where: {
|
||||
userId: user.id
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(connection);
|
||||
} catch (error) {
|
||||
console.log("[CONNECTION/TWITCH]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
85
app/api/settings/connections/twitch/route.ts
Normal file
85
app/api/settings/connections/twitch/route.ts
Normal file
@ -0,0 +1,85 @@
|
||||
import axios from "axios"
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
const user = await fetchUserUsingAPI(req)
|
||||
if (!user) {
|
||||
console.log("TWITCH CONNECT", user)
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const { searchParams } = new URL(req.url)
|
||||
let userId = searchParams.get('id')
|
||||
|
||||
if (userId == null) {
|
||||
if (user != null) {
|
||||
userId = user.id as string;
|
||||
}
|
||||
}
|
||||
|
||||
const connection = await db.twitchConnection.findFirst({
|
||||
where: {
|
||||
userId: userId as string
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(connection);
|
||||
} catch (error) {
|
||||
console.log("[CONNECTION/TWITCH]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const { id, secret } = await req.json();
|
||||
const user = await fetchUserUsingAPI(req)
|
||||
console.log("userrr:", user)
|
||||
if (!user) {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
console.log(id, secret)
|
||||
let response = null;
|
||||
try {
|
||||
response = await axios.post("https://id.twitch.tv/oauth2/token", {
|
||||
client_id: id,
|
||||
client_secret: secret,
|
||||
grant_type: "client_credentials"
|
||||
});
|
||||
console.log(response.data)
|
||||
} catch (error) {
|
||||
console.log("[CONNECTIONS/TWITCH/TOKEN]", error);
|
||||
return;
|
||||
}
|
||||
|
||||
console.log(user.username)
|
||||
let info = await axios.get("https://api.twitch.tv/helix/users?login=" + user.username, {
|
||||
headers: {
|
||||
"Authorization": "Bearer " + response.data['access_token'],
|
||||
"Client-Id": id
|
||||
}
|
||||
})
|
||||
console.log(info.data.data)
|
||||
const broadcasterId = info.data.data[0]['id']
|
||||
const username = info.data.data[0]['login']
|
||||
|
||||
const connection = await db.twitchConnection.create({
|
||||
data: {
|
||||
id,
|
||||
secret,
|
||||
userId: user.id as string,
|
||||
broadcasterId,
|
||||
username
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(connection);
|
||||
} catch (error) {
|
||||
console.log("[CONNECTION/TWITCH]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
56
app/api/settings/tts/filter/badges/route.ts
Normal file
56
app/api/settings/tts/filter/badges/route.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import axios from "axios"
|
||||
import { currentUser } from "@/lib/current-user";
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
const user = await currentUser();
|
||||
if (!user) {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
let badges = await axios.get("https://api.twitch.tv/helix/chat/badges")
|
||||
|
||||
|
||||
const badgesData = await db.ttsBadgeFilter.findMany({
|
||||
where: {
|
||||
data: {
|
||||
userId: user.id
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// return NextResponse.json(badgesData);
|
||||
return new NextResponse("Bad Request", { status: 400 });
|
||||
} catch (error) {
|
||||
console.log("[CONNECTION/TWITCH]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
const user = await currentUser();
|
||||
const badges = await req.json();
|
||||
|
||||
console.log("BADGES", badges);
|
||||
if (!user) {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
// const badgesData = await db.tTSBadgeFilter.createMany({
|
||||
// badges.map((badgeName, value) => {
|
||||
// data: {
|
||||
// userId: user.id
|
||||
// }
|
||||
// })
|
||||
// });
|
||||
|
||||
// return NextResponse.json(badgesData);
|
||||
return new NextResponse("Bad Request", { status: 400 });
|
||||
} catch (error) {
|
||||
console.log("[CONNECTION/TWITCH]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
42
app/api/token/[id]/route.ts
Normal file
42
app/api/token/[id]/route.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { db } from "@/lib/db"
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request, { params } : { params: { id: string } }) {
|
||||
try {
|
||||
let id = req.headers?.get('x-api-key')
|
||||
if (id == null) {
|
||||
return NextResponse.json(null);
|
||||
}
|
||||
|
||||
const tokens = await db.apiKey.findFirst({
|
||||
where: {
|
||||
id: id
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(tokens);
|
||||
} catch (error) {
|
||||
console.log("[TOKEN/GET]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(req: Request, { params } : { params: { id: string } }) {
|
||||
try {
|
||||
const { id } = params
|
||||
const user = await fetchUserUsingAPI(req)
|
||||
|
||||
const token = await db.apiKey.delete({
|
||||
where: {
|
||||
id,
|
||||
userId: user?.id
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(token);
|
||||
} catch (error) {
|
||||
console.log("[TOKEN/DELETE]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
34
app/api/token/bot/route.ts
Normal file
34
app/api/token/bot/route.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { db } from "@/lib/db"
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
const user = await fetchUserUsingAPI(req);
|
||||
if (!user) {
|
||||
return new NextResponse("Unauthorized", { status: 401 });
|
||||
}
|
||||
|
||||
const api = await db.twitchConnection.findFirst({
|
||||
where: {
|
||||
userId: user.id
|
||||
}
|
||||
})
|
||||
|
||||
if (!api) {
|
||||
return new NextResponse("Forbidden", { status: 403 });
|
||||
}
|
||||
|
||||
const data = {
|
||||
client_id: process.env.TWITCH_BOT_CLIENT_ID,
|
||||
client_secret: process.env.TWITCH_BOT_CLIENT_SECRET,
|
||||
access_token: api.accessToken,
|
||||
refresh_token: api.refreshToken,
|
||||
broadcaster_id: api.broadcasterId
|
||||
}
|
||||
return NextResponse.json(data);
|
||||
} catch (error) {
|
||||
console.log("[TOKENS/GET]", error);
|
||||
return new NextResponse("Internal Error", { status: 500 });
|
||||
}
|
||||
}
|
63
app/api/token/route.ts
Normal file
63
app/api/token/route.ts
Normal file
@ -0,0 +1,63 @@
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function POST(req: Request) {
|
||||
try {
|
||||
let { userId, label } = await req.json();
|
||||
|
||||
if (userId == null) {
|
||||
const user = await fetchUserUsingAPI(req);
|
||||
if (user != null) {
|
||||
userId = user.id;
|
||||
}
|
||||
}
|
||||
|
||||
const id = generateToken()
|
||||
const token = await db.apiKey.create({
|
||||
data: {
|
||||
id,
|
||||
label,
|
||||
userId: userId as string
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(token);
|
||||
} catch (error) {
|
||||
console.log("[TOKEN/POST]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(req: Request) {
|
||||
try {
|
||||
let { id } = await req.json();
|
||||
const user = await fetchUserUsingAPI(req);
|
||||
if (!id || !user) {
|
||||
return NextResponse.json(null)
|
||||
}
|
||||
|
||||
const token = await db.apiKey.delete({
|
||||
where: {
|
||||
id,
|
||||
userId: user?.id
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(token);
|
||||
} catch (error) {
|
||||
console.log("[TOKEN/DELETE]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
||||
|
||||
export function generateToken() {
|
||||
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
|
||||
var string_length = 32;
|
||||
var randomstring = '';
|
||||
for (var i = 0; i < string_length; i++) {
|
||||
var rnum = Math.floor(Math.random() * chars.length);
|
||||
randomstring += chars[rnum];
|
||||
}
|
||||
return randomstring;
|
||||
}
|
30
app/api/tokens/route.ts
Normal file
30
app/api/tokens/route.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import fetchUserUsingAPI from "@/lib/validate-api";
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request) {
|
||||
try {
|
||||
const { searchParams } = new URL(req.url)
|
||||
let userId = searchParams.get('userId')
|
||||
|
||||
if (userId == null) {
|
||||
const user = await fetchUserUsingAPI(req);
|
||||
if (user != null) {
|
||||
userId = user.id as string;
|
||||
}
|
||||
}
|
||||
|
||||
console.log("TOKEN KEY:", userId)
|
||||
|
||||
const tokens = await db.apiKey.findMany({
|
||||
where: {
|
||||
userId: userId as string
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(tokens);
|
||||
} catch (error) {
|
||||
console.log("[TOKENS/GET]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
22
app/api/validate/route.ts
Normal file
22
app/api/validate/route.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import { db } from "@/lib/db"
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function GET(req: Request, { params } : { params: { id: string } }) {
|
||||
try {
|
||||
let id = req.headers.get('x-api-key')
|
||||
if (id == null) {
|
||||
return NextResponse.json(null);
|
||||
}
|
||||
|
||||
const tokens = await db.apiKey.findFirst({
|
||||
where: {
|
||||
id: id as string
|
||||
}
|
||||
});
|
||||
|
||||
return NextResponse.json(tokens);
|
||||
} catch (error) {
|
||||
console.log("[VALIDATE/GET]", error);
|
||||
return new NextResponse("Internal Error", { status: 500});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user