From aab83ce587218616da25fdecd66da67b02ddce7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Leandro=20Ant=C3=B4nio=20Farias=20Machado?= Date: Mon, 31 Jul 2023 11:07:53 -0300 Subject: [PATCH] feat: create admin if it doesn't exists --- .../services/controller/internal/api/api.go | 55 ++++++++++++++++--- frontend/src/contexts/auth-context.js | 28 +++++++++- frontend/src/pages/auth/login.js | 34 +++++++++++- 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/backend/services/controller/internal/api/api.go b/backend/services/controller/internal/api/api.go index d50850a..d5e4c8a 100644 --- a/backend/services/controller/internal/api/api.go +++ b/backend/services/controller/internal/api/api.go @@ -2,6 +2,13 @@ package api import ( "encoding/json" + "log" + "net/http" + "strconv" + "strings" + "sync" + "time" + "github.com/gorilla/mux" "github.com/leandrofars/oktopus/internal/api/auth" "github.com/leandrofars/oktopus/internal/api/cors" @@ -12,12 +19,6 @@ import ( "github.com/leandrofars/oktopus/internal/utils" "go.mongodb.org/mongo-driver/mongo" "google.golang.org/protobuf/proto" - "log" - "net/http" - "strconv" - "strings" - "sync" - "time" ) type Api struct { @@ -65,9 +66,8 @@ func StartApi(a Api) { authentication := r.PathPrefix("/api/auth").Subrouter() authentication.HandleFunc("/login", a.generateToken).Methods("PUT") authentication.HandleFunc("/register", a.registerUser).Methods("POST") - // Keep the line above commented to avoid people get unintended admin privileges. - // Uncomment it only once for you to get admin privileges and create new users. - //authentication.HandleFunc("/admin/register", a.registerAdminUser).Methods("POST") + authentication.HandleFunc("/admin/register", a.registerAdminUser).Methods("POST") + authentication.HandleFunc("/admin/exists", a.adminUserExists).Methods("GET") iot := r.PathPrefix("/api/device").Subrouter() iot.HandleFunc("", a.retrieveDevices).Methods("GET") iot.HandleFunc("/{sn}/get", a.deviceGetMsg).Methods("PUT") @@ -757,6 +757,20 @@ func (a *Api) registerAdminUser(w http.ResponseWriter, r *http.Request) { return } + users, err := a.Db.FindAllUsers() + if err != nil { + log.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + adminExists := adminUserExists(users) + if adminExists { + log.Println("There might exist only one admin") + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode("There might exist only one admin") + return + } + user.Level = AdminUser if err := user.HashPassword(user.Password); err != nil { @@ -770,6 +784,29 @@ func (a *Api) registerAdminUser(w http.ResponseWriter, r *http.Request) { } } +func adminUserExists(users []map[string]interface{}) bool { + for _, x := range users { + if x["level"].(int32) == AdminUser { + log.Println("Admin exists") + return true + } + } + return false +} + +func (a *Api) adminUserExists(w http.ResponseWriter, r *http.Request) { + + users, err := a.Db.FindAllUsers() + if err != nil { + log.Println(err) + w.WriteHeader(http.StatusInternalServerError) + return + } + adminExits := adminUserExists(users) + json.NewEncoder(w).Encode(adminExits) + return +} + type TokenRequest struct { Email string `json:"email"` Password string `json:"password"` diff --git a/frontend/src/contexts/auth-context.js b/frontend/src/contexts/auth-context.js index 6dcc1e5..1b8f7a0 100644 --- a/frontend/src/contexts/auth-context.js +++ b/frontend/src/contexts/auth-context.js @@ -1,5 +1,6 @@ import { createContext, useContext, useEffect, useReducer, useRef } from 'react'; import PropTypes from 'prop-types'; +import { useRouter } from 'next/router'; const HANDLERS = { INITIALIZE: 'INITIALIZE', @@ -63,6 +64,7 @@ export const AuthProvider = (props) => { const { children } = props; const [state, dispatch] = useReducer(reducer, initialState); const initialized = useRef(false); + const router = useRouter(); const initialize = async () => { // Prevent from calling twice in development mode with React.StrictMode enabled @@ -177,7 +179,31 @@ export const AuthProvider = (props) => { }; const signUp = async (email, name, password) => { - throw new Error('Sign up is not implemented'); + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); + + var raw = JSON.stringify({ + "email": email, + "password": password, + "name": name + }); + + var requestOptions = { + method: 'POST', + headers: myHeaders, + body: raw, + redirect: 'follow' + }; + + let result = await fetch(process.env.NEXT_PUBLIC_REST_ENPOINT+"/auth/admin/register", requestOptions) + + if (result.status == 200) { + router.push("/auth/login") + }else{ + const content = await result.json() + throw new Error(content); + } + }; const signOut = () => { diff --git a/frontend/src/pages/auth/login.js b/frontend/src/pages/auth/login.js index 4d7f8e3..b2abe4d 100644 --- a/frontend/src/pages/auth/login.js +++ b/frontend/src/pages/auth/login.js @@ -1,4 +1,4 @@ -import { useCallback, useState } from 'react'; +import { useCallback, useEffect, useState } from 'react'; import Head from 'next/head'; import NextLink from 'next/link'; import { useRouter } from 'next/navigation'; @@ -67,6 +67,38 @@ const Page = () => { [auth, router] ); + const [adminExists, setAdminExists] = useState(true) + + const initialize = async () => { + await adminUserExists() + } + + const adminUserExists = async () => { + var myHeaders = new Headers(); + myHeaders.append("Content-Type", "application/json"); + + var requestOptions = { + method: 'GET', + headers: myHeaders, + redirect: 'follow', + }; + + let result = await (await fetch(`${process.env.NEXT_PUBLIC_REST_ENPOINT}/auth/admin/exists`, requestOptions)) + let content = await result.json() + console.log("content: ", content) + if (result.status != 200) { + throw new Error(content); + }else{ + if (!content){ + router.push("/auth/register") + } + } +} + + useEffect(()=>{ + initialize() + },[]) + return ( <>