diff --git a/cmd/reset-admin-password/main.go b/cmd/reset-admin-password/main.go index a3bb79d..a5cfb55 100644 --- a/cmd/reset-admin-password/main.go +++ b/cmd/reset-admin-password/main.go @@ -29,7 +29,7 @@ func main() { os.Exit(1) } if !newAdminUserCreated { - resetMFA, err := getLine("Also remove MFA if present? [Y/n] ") + resetMFA, err := getLine("\nAlso remove MFA if present? [Y/n] ") if err != nil { fmt.Printf("Failed to changed admin password: %s", err) os.Exit(1) diff --git a/pkg/commands/resetpassword.go b/pkg/commands/resetpassword.go index af8ac99..fbef43e 100644 --- a/pkg/commands/resetpassword.go +++ b/pkg/commands/resetpassword.go @@ -20,6 +20,9 @@ func ResetPassword(appDir, password string) (bool, error) { if err != nil { return adminCreated, fmt.Errorf("config retrieval error: %s", err) } + c.Storage = &rest.Storage{ + Client: localstorage, + } c.UserStore, err = users.NewUserStore(localstorage, -1) if err != nil { return adminCreated, fmt.Errorf("userstore initialization error: %s", err) diff --git a/pkg/rest/setup.go b/pkg/rest/setup.go index 1792609..7149b0d 100644 --- a/pkg/rest/setup.go +++ b/pkg/rest/setup.go @@ -41,6 +41,10 @@ func (c *Context) contextHandler(w http.ResponseWriter, r *http.Request) { switch c.CloudType { case "digitalocean": // check if the hashtag is set if contextReq.TagHash != "" { + if !strings.HasPrefix(contextReq.TagHash, "vpnsecret-") { + c.returnError(w, fmt.Errorf("tag doesn't have the correct prefix. The tag needs to start with 'vpnsecret-'"), http.StatusUnauthorized) + return + } accessGranted, err = license.HasDigitalOceanTagSet(http.Client{Timeout: 5 * time.Second}, contextReq.TagHash) if err != nil { c.returnError(w, fmt.Errorf("could not retrieve tags at this time: %s", err), http.StatusUnauthorized) @@ -60,6 +64,9 @@ func (c *Context) contextHandler(w http.ResponseWriter, r *http.Request) { } if strings.TrimPrefix(instanceID, "i-") == strings.TrimPrefix(contextReq.InstanceID, "i-") { accessGranted = true + } else { + c.returnError(w, fmt.Errorf("instance id doesn't match"), http.StatusUnauthorized) + return } } } diff --git a/pkg/rest/setup_test.go b/pkg/rest/setup_test.go index 0465b7b..2e14bca 100644 --- a/pkg/rest/setup_test.go +++ b/pkg/rest/setup_test.go @@ -233,7 +233,7 @@ func TestContextHandlerSetupAWSInstanceID(t *testing.T) { func TestContextHandlerSetupDigitalOceanTag(t *testing.T) { ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if r.RequestURI == "/metadata/v1/tags" { - w.Write([]byte("this-is-a-secret-tag")) + w.Write([]byte("vpnsecret-this-is-a-secret-tag")) return } w.WriteHeader(http.StatusBadRequest) @@ -258,7 +258,7 @@ func TestContextHandlerSetupDigitalOceanTag(t *testing.T) { c.CloudType = "digitalocean" payload := ContextRequest{ - TagHash: "this-is-a-secret-tag", + TagHash: "vpnsecret-this-is-a-secret-tag", AdminPassword: "adminPassword", } payloadBytes, err := json.Marshal(payload) diff --git a/webapp/src/AppInit/SetAdminPassword.tsx b/webapp/src/AppInit/SetAdminPassword.tsx index 9d3872d..dd37bc9 100644 --- a/webapp/src/AppInit/SetAdminPassword.tsx +++ b/webapp/src/AppInit/SetAdminPassword.tsx @@ -5,26 +5,23 @@ import axios from 'axios'; import { AppSettings } from '../Constants/Constants'; import { useMutation, - useQueryClient, } from '@tanstack/react-query' type Props = { onChangeStep: (newType: number) => void; - secret: string + secrets: SetupResponse }; -export function SetAdminPassword({onChangeStep, secret}: Props) { - const queryClient = useQueryClient() +export function SetAdminPassword({onChangeStep, secrets}: Props) { const [password, setPassword] = useState(""); const [password2, setPassword2] = useState(""); const [passwordError, setPasswordError] = useState(""); const [password2Error, setPassword2Error] = useState(""); const passwordMutation = useMutation({ mutationFn: (newPassword: string) => { - return axios.post(AppSettings.url + '/context', {secret: secret, adminPassword: newPassword, hostname: window.location.host, protocol: window.location.protocol}) + return axios.post(AppSettings.url + '/context', {...secrets, adminPassword: newPassword, hostname: window.location.host, protocol: window.location.protocol}) }, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['context'] }) onChangeStep(2) }, onError: (error) => { @@ -40,6 +37,7 @@ export function SetAdminPassword({onChangeStep, secret}: Props) { } if(password === "") { setPasswordError("admin password cannot be blank") + return } passwordMutation.mutate(password) } diff --git a/webapp/src/AppInit/SetSecret.tsx b/webapp/src/AppInit/SetSecret.tsx index 327f76a..9624204 100644 --- a/webapp/src/AppInit/SetSecret.tsx +++ b/webapp/src/AppInit/SetSecret.tsx @@ -1,27 +1,19 @@ -import { Text, Title, TextInput, Button, Card, Grid, Container, Center, Alert, ActionIcon } from '@mantine/core'; -import { useClipboard } from '@mantine/hooks'; -import { TbCheck, TbCopy } from 'react-icons/tb'; +import { Text, Title, TextInput, Button, Card, Grid, Container, Center, Alert } from '@mantine/core'; import classes from './SetupBanner.module.css'; import {useState} from 'react'; import axios, { AxiosError } from 'axios'; import { AppSettings } from '../Constants/Constants'; import { - useQueryClient, useMutation, } from '@tanstack/react-query' import { TbInfoCircle } from 'react-icons/tb'; type Props = { onChangeStep: (newType: number) => void; - onChangeSecret: (newType: string) => void; + onChangeSecrets: (newType: SetupResponse) => void; cloudType: string; }; -type SetupResponse = { - secret: string; - tagHash: string; - instanceID: string; -} type SetupResponseError = { error: string; } @@ -34,24 +26,21 @@ const randomHex = (length:number) => { if(h.length==1) { h='0'+h; } hexstring+=h; } - return hexstring; + return "vpnsecret-"+hexstring; } -export function SetSecret({onChangeStep, onChangeSecret, cloudType}: Props) { - const clipboard = useClipboard({ timeout: 120000 }); - const queryClient = useQueryClient() +export function SetSecret({onChangeStep, onChangeSecrets, cloudType}: Props) { const [setupResponse, setSetupResponse] = useState({secret: "", tagHash: "", instanceID: ""}); const [secretError, setSecretError] = useState(""); const [randomHexValue] = useState(randomHex(16)) const secretMutation = useMutation({ - mutationFn: (setupResponse: SetupResponse) => { + mutationFn: (setupResponseParam: SetupResponse) => { setSecretError("") - return axios.post(AppSettings.url + '/context', setupResponse) + return axios.post(AppSettings.url + '/context', setupResponseParam) }, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['context'] }) - onChangeSecret(setupResponse.secret) + onSuccess: (_, setupResponseParam) => { + onChangeSecrets(setupResponseParam) onChangeStep(1) }, onError: (error:AxiosError) => { @@ -150,21 +139,16 @@ export function SetSecret({onChangeStep, onChangeSecret, cloudType}: Props) { {hasMoreOptions ? "Option 2: " : ""}Without SSH Access - Add the following tag to the droplet by going to the droplet settings and opening the Tags page. + Add the following tag to the droplet by going to the droplet settings and opening the Tags page. You can remove the tag once the setup is complete. {secretMutation.isPending ? (
Checking tag...
) : (
clipboard.copy(randomHexValue)}> - { clipboard.copied ? : } - - } />
diff --git a/webapp/src/AppInit/SetupBanner.tsx b/webapp/src/AppInit/SetupBanner.tsx index 2360d6a..9ebf57c 100644 --- a/webapp/src/AppInit/SetupBanner.tsx +++ b/webapp/src/AppInit/SetupBanner.tsx @@ -10,7 +10,7 @@ type Props = { export function SetupBanner({onCompleted, cloudType}:Props) { const [step, setStep] = useState(0); - const [secret, setSecret] = useState(""); + const [secrets, setSecrets] = useState({secret: "", tagHash: "", instanceID: ""}); React.useEffect(() => { if(step === 2) { @@ -19,8 +19,8 @@ export function SetupBanner({onCompleted, cloudType}:Props) { }, [step]); if(step === 0) { - return + return } else if(step === 1) { - return + return } } \ No newline at end of file diff --git a/webapp/src/types/SetupRequest.tsx b/webapp/src/types/SetupRequest.tsx new file mode 100644 index 0000000..e7f1bf5 --- /dev/null +++ b/webapp/src/types/SetupRequest.tsx @@ -0,0 +1,5 @@ +type SetupResponse = { + secret: string; + tagHash: string; + instanceID: string; + } \ No newline at end of file