Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notifications #20

Merged
merged 9 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions SecureSend/ClientApp/src/App.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup lang="ts">
import { provide, ref } from "vue";
import { RouterView } from "vue-router";

provide("isLoading", ref<boolean>(false));
</script>

<template>
<div
id="alert-container"
class="absolute z-50 h-fit top-1 left-1 flex flex-col"
></div>
<RouterView />
<!-- <FileUpload></FileUpload> -->
</template>
13 changes: 13 additions & 0 deletions SecureSend/ClientApp/src/assets/icons/InfoIcon.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<template>
<svg
class="flex-shrink-0 inline w-4 h-4"
aria-hidden="true"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 20"
>
<path
d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5ZM9.5 4a1.5 1.5 0 1 1 0 3 1.5 1.5 0 0 1 0-3ZM12 15H8a1 1 0 0 1 0-2h1v-3H8a1 1 0 0 1 0-2h2a1 1 0 0 1 1 1v4h1a1 1 0 0 1 0 2Z"
/>
</svg>
</template>
75 changes: 75 additions & 0 deletions SecureSend/ClientApp/src/components/AlertNotification.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<template>
<Transition>
<div
v-show="isShown"
ref="root"
:class="`flex items-center gap-2 w-fit p-3 mb-4 text-sm border rounded-lg bg-gray-800 ${textColor}`"
role="alert"
>
<InfoIcon></InfoIcon>
<span class="sr-only">Info</span>
<span class="font-medium">
<slot></slot>
</span>
<button
@click="onCloseClick()"
type="button"
class="p-1 rounded-lg focus:ring-2 focus:ring-gray-300 inline-flex items-center justify-center h-6 w-6 text-gray-500 hover:text-white bg-gray-800 hover:bg-gray-700"
data-dismiss-target="#toast-success"
aria-label="Close"
>
<span class="sr-only">Close</span>
<CloseIcon class="w-3 h-3"></CloseIcon>
</button>
</div>
</Transition>
</template>

<style scoped>
.v-enter-active,
.v-leave-active {
transition: opacity 1s ease;
}

.v-enter-from,
.v-leave-to {
opacity: 0;
}
</style>

<script setup lang="ts">
import { computed, ref, render } from "vue";
import CloseIcon from "@/assets/icons/CloseIcon.vue";
import { DialogType } from "../utils/composables/useAlert";
import InfoIcon from "@/assets/icons/InfoIcon.vue";

defineEmits(["onCloseClick"]);

const root = ref();

const textColor = computed(() => {
if (props.type === DialogType.Danger) return "text-red-400 border-red-800";
if (props.type === DialogType.Success)
return "text-green-400 border-green-800";
});

const isShown = ref<boolean>(false);

requestAnimationFrame(() => (isShown.value = true));

const timeout = setTimeout(() => onCloseClick(), 30000);

const onCloseClick = () => {
clearInterval(timeout);
isShown.value = false;
setTimeout(() => {
const wrapper = root.value;
render(null, wrapper);
wrapper.parentElement.remove();
}, 1000);
};

const props = defineProps<{
type: DialogType;
}>();
</script>
2 changes: 1 addition & 1 deletion SecureSend/ClientApp/src/components/ConfirmModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ defineEmits(["closeClick"]);
<div
tabindex="-1"
aria-hidden="true"
class="absolute h-screen w-screen flex items-center justify-center bg-gray-900/50"
class="absolute z-40 h-screen w-screen flex items-center justify-center bg-gray-900/50"
>
<div class="relative w-full max-w-2xl max-h-full">
<!-- Modal content -->
Expand Down
14 changes: 11 additions & 3 deletions SecureSend/ClientApp/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import "./assets/main.css";

import { createApp } from "vue";
import { createApp, inject, ref, type Ref } from "vue";
import App from "./App.vue";
import router from "./router";
import { useAlert } from "./utils/composables/useAlert";

const app = createApp(App);

app.config.errorHandler = (error) => {
console.log("global error", error);
const { openDanger } = useAlert();

const isLoading = ref<boolean>(false);

app.provide("isLoading", isLoading);

app.config.errorHandler = () => {
isLoading!.value = false;
openDanger("Something went wrong");
};

const registerServiceWorker = async () => {
Expand Down
2 changes: 1 addition & 1 deletion SecureSend/ClientApp/src/services/SecureSendService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export abstract class SecureSendService {
static viewSecureUpload = async (
viewSecureUpload: ViewSecureUpload
): Promise<SecureUploadDto> => {
return await fetchWrapper.put(
return await fetchWrapper.put<SecureUploadDto>(
`${endpoints.secureSend}?id=${viewSecureUpload.id}`
);
};
Expand Down
41 changes: 41 additions & 0 deletions SecureSend/ClientApp/src/utils/composables/useAlert.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import AlertNotificationVue from "@/components/AlertNotification.vue";
import { h, render, type VNode } from "vue";

export enum DialogType {
Success,
Danger,
}

function mountComponent(component: VNode) {
const alertContainer = document.getElementById("alert-container");
const alert = document.createElement("div");
alertContainer!.appendChild(alert);
render(component, alert);
}

export interface UseAlertReturn {
openDanger: (message: string) => void;
openSuccess: (message: string) => void;
}

export function useAlert(): UseAlertReturn {
return {
openDanger(message: string) {
const component = h(
AlertNotificationVue,
{ type: DialogType.Danger },
{ default: () => message }
);
// component.component.
mountComponent(component);
},
openSuccess(message: string) {
const component = h(
AlertNotificationVue,
{ type: DialogType.Success },
{ default: () => message }
);
mountComponent(component);
},
};
}
60 changes: 16 additions & 44 deletions SecureSend/ClientApp/src/utils/splitFile.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// This source code is taken from Firefox Send (https://github.com/mozilla/send) and slightly modified.

export default async function splitFile(
file: File,
chunkSize: number,
Expand All @@ -10,49 +8,23 @@ export default async function splitFile(
) => void,
transformer?: (chunk: Uint8Array, chunkIndex: number) => any
) {
return new Promise((resolve, reject) => {
const fileSize = file.size;
const totalChunks = Math.ceil(fileSize / chunkSize);
console.log(totalChunks);
let offset = 0;

const readChunk = () => {
const r = new FileReader();
const blob = file.slice(offset, chunkSize + offset);
r.onload = readEventHandler;
r.readAsArrayBuffer(blob);
};

const readEventHandler = async (evt: any) => {
if (evt.target.error == null) {
const sequenceNumber = offset / chunkSize;
offset += evt.target.result.byteLength;
let data = new Uint8Array(evt.target.result);

if (transformer) {
try {
data = await transformer(data, sequenceNumber);
await callback(data, sequenceNumber, totalChunks);
} catch (error) {
reject(error);
}
}
} else {
// Read error.
return;
}
const fileSize = file.size;
const totalChunks = Math.ceil(fileSize / chunkSize);
let offset = 0;

if (offset >= fileSize) {
// Done reading file.
resolve(undefined);
return;
}
while (offset < fileSize) {
const buffer = await file.slice(offset, offset + chunkSize).arrayBuffer();
await readEventHandler(buffer);
}

// Off to the next chunk.
readChunk();
};
async function readEventHandler(buffer: ArrayBuffer) {
const sequenceNumber = offset / chunkSize;
offset += buffer.byteLength;
let data = new Uint8Array(buffer);

// Let's start reading the first block.
readChunk();
});
if (transformer) {
data = await transformer(data, sequenceNumber);
await callback(data, sequenceNumber, totalChunks);
}
}
}
32 changes: 22 additions & 10 deletions SecureSend/ClientApp/src/views/FileUploadView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ import { useConfirmDialog } from "@/utils/composables/useConfirmDialog";
import SimpleInput from "@/components/SimpleInput.vue";
import { inject } from "vue";
import LoadingIndicator from "@/components/LoadingIndicator.vue";
import { useAlert } from "@/utils/composables/useAlert";

interface IMappedFormValues {
expiryDate: string;
Expand All @@ -85,11 +86,18 @@ interface IMappedFormValues {

const { isRevealed, reveal, confirm } = useConfirmDialog();

const salt = crypto.getRandomValues(new Uint8Array(16));
console.log(salt);
const { openSuccess } = useAlert();

let salt = crypto.getRandomValues(new Uint8Array(16));
let keychain: AuthenticatedSecretKeyCryptography;

const step = ref<number>(0);

let uuid = self.crypto.randomUUID();
const uploadStatus = ref<number>();

const files = ref(new Map<File, number | string | boolean>());

let downloadUrl: string;

const isLoading = inject<Ref<boolean>>("isLoading");
Expand Down Expand Up @@ -141,21 +149,25 @@ const onSubmit = handleSubmit(async (values: IMappedFormValues) => {
const { data } = await reveal();
console.log(data);
if (data) {
resetForm({ values: getInitialValues() });
step.value = 0;
await formReset();
openSuccess("Upload successful");
return;
}
console.log("dialog closed");
}
if (step.value < 2) step.value++;
});

const copyToClipboard = () => navigator.clipboard.writeText(downloadUrl);

const uuid = self.crypto.randomUUID();
const uploadStatus = ref<number>();
const formReset = async () => {
resetForm({ values: getInitialValues() });
step.value = 0;
salt = crypto.getRandomValues(new Uint8Array(16));
uuid = self.crypto.randomUUID();
};

const files = ref(new Map<File, number | string | boolean>());
const copyToClipboard = () => {
navigator.clipboard.writeText(downloadUrl);
openSuccess("Link copied to clipboard");
};

const onFilesChange = (event: any) => {
files.value.clear();
Expand Down
Loading