Skip to content
Draft
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
19 changes: 17 additions & 2 deletions client/src/common/validators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,9 @@ export const claimAndBootstrapLinkValidator: IValidator = async function (value:
result.value.tag === ParsedParsecAddrTag.InvitationUser ||
result.value.tag === ParsedParsecAddrTag.InvitationDevice ||
result.value.tag === ParsedParsecAddrTag.AsyncEnrollment ||
// Not a join link but it we can use it as a backup
result.value.tag === ParsedParsecAddrTag.TOTPReset)
// Not join links but we can use this as a backup
result.value.tag === ParsedParsecAddrTag.TOTPReset ||
result.value.tag === ParsedParsecAddrTag.InvitationShamirRecovery)
) {
return { validity: Validity.Valid };
}
Expand Down Expand Up @@ -336,3 +337,17 @@ export const totpResetLinkValidator: IValidator = async function (value: string)
}
return { validity: Validity.Invalid, reason: 'HomePage.organizationRequest.totp.invalidLink' };
};

export const shamirRecoveryLinkValidator: IValidator = async function (value: string) {
value = value.trim();
if (value.length === 0) {
return { validity: Validity.Intermediate };
}
const result = await parseParsecAddr(value);
if (result.ok) {
return result.value.tag === ParsedParsecAddrTag.InvitationShamirRecovery
? { validity: Validity.Valid }
: { validity: Validity.Invalid };
}
return { validity: Validity.Invalid, reason: 'HomePage.shamir.invalidLink' };
};
2 changes: 0 additions & 2 deletions client/src/components/devices/ChooseAuthentication.vue
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,6 @@ import {
DevicePrimaryProtectionStrategyTag,
DeviceSaveStrategy,
OpenBaoAuthConfigTag,
ParsecAddr,
PrimaryProtectionStrategy,
ServerConfig,
constructSaveStrategy,
Expand Down Expand Up @@ -198,7 +197,6 @@ const props = defineProps<{
showTitle?: boolean;
activeAuth?: DevicePrimaryProtectionStrategyTag;
serverConfig?: ServerConfig;
serverAddr: ParsecAddr;
}>();

defineExpose({
Expand Down
5 changes: 0 additions & 5 deletions client/src/components/profile/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,3 @@ export enum AuthenticationCardState {
Unavailable = 'unavailable',
Forbidden = 'forbidden',
}

export enum ShamirTab {
Self = 'shamir-tab-self',
Others = 'shamir-tab-others',
}
83 changes: 83 additions & 0 deletions client/src/components/shamir/ShamirCodeExchangeGuest.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<!-- Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS -->

<template>
<div
v-if="step === Steps.ChooseCode"
class="choose-code"
>
<sas-code-choice
:choices="claimer.greeterSasChoices"
@select="selectGreeterCode"
/>
</div>

<div
v-if="step === Steps.ProvideCode"
class="provide-code"
>
<sas-code-provide :code="claimer.claimerSasCode" />
</div>
</template>

<script lang="ts">
export enum CodeExchangeInterruptedReason {
NoCodeSelected = 'no-code-selected',
WrongCodeSelected = 'wrong-code-selected',
SignifyTrustFailed = 'signify-trust-failed',
WaitTrustFailed = 'wait-trust-failed',
}
</script>

<script setup lang="ts">
import SasCodeChoice from '@/components/sas-code/SasCodeChoice.vue';
import SasCodeProvide from '@/components/sas-code/SasCodeProvide.vue';
import { ShamirClaimer } from '@/parsec';
import { nextTick, ref } from 'vue';

enum Steps {
ChooseCode = 'shamir-guest-choose-code',
ProvideCode = 'shamir-guest-provide-code',
}

const step = ref<Steps>(Steps.ChooseCode);

const props = defineProps<{
claimer: ShamirClaimer;
}>();

const emits = defineEmits<{
(e: 'interrupted', reason: CodeExchangeInterruptedReason): void;
(e: 'codeExchanged'): void;
}>();

async function selectGreeterCode(code: string | null): Promise<void> {
if (code === null) {
await props.claimer.denyTrust();
emits('interrupted', CodeExchangeInterruptedReason.NoCodeSelected);
return;
}
if (code !== props.claimer.greeterSasCode) {
await props.claimer.denyTrust();
emits('interrupted', CodeExchangeInterruptedReason.WrongCodeSelected);
return;
}
console.log('SIGNIFY TRUST');
const result = await props.claimer.signifyTrust();
if (!result) {
emits('interrupted', CodeExchangeInterruptedReason.SignifyTrustFailed);
return;
}
console.log('SIGNIFY TRUST RETURNED');
step.value = Steps.ProvideCode;
await nextTick();
console.log('WAIT TRUST', props.claimer.claimerSasCode);
const waitResult = await props.claimer.waitGreeterTrust();
if (!waitResult.ok) {
emits('interrupted', CodeExchangeInterruptedReason.WaitTrustFailed);
return;
}
emits('codeExchanged');
}
</script>

<style scoped lang="scss"></style>
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@
</template>

<script setup lang="ts">
import ShamirSelfDisplay from '@/components/profile/ShamirSelfDisplay.vue';
import ShamirSetup from '@/components/profile/ShamirSetup.vue';
import ShamirSelfDisplay from '@/components/shamir/ShamirSelfDisplay.vue';
import ShamirSetup from '@/components/shamir/ShamirSetup.vue';
import { getSelfShamirRecovery, SelfShamirRecoveryInfo, SelfShamirRecoveryInfoTag } from '@/parsec';
import { InformationManager } from '@/services/informationManager';
import { MsReportText, MsReportTheme } from 'megashark-lib';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,8 @@

<script setup lang="ts">
import ShamirIconCircle from '@/assets/images/shamir-icon-circle.svg?raw';
import { SelfShamirRecoveryInfo } from '@/parsec';
import { SelfShamirRecoveryInfo, SelfShamirRecoveryInfoTag } from '@/parsec';
import { deleteSelfShamirRecovery } from '@/parsec/shamir';
import { SelfShamirRecoveryInfoTag } from '@/plugins/libparsec';
import { IonButton, IonIcon, IonItem, IonList, IonText } from '@ionic/vue';
import { checkmarkCircle, informationCircle, shieldCheckmark } from 'ionicons/icons';
import { Answer, askQuestion, MsImage, MsReportText, MsReportTheme } from 'megashark-lib';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@

<script setup lang="ts">
import ShamirIconCircle from '@/assets/images/shamir-icon-circle.svg?raw';
import ShamirSetupSearchDropdown from '@/components/profile/ShamirSetupSearchDropdown.vue';
import ShamirSetupSearchDropdown from '@/components/shamir/ShamirSetupSearchDropdown.vue';
import { getClientInfo, listUsers, UserInfo, UserProfile } from '@/parsec';
import { getRequiredShamirThreshold, setupShamirRecovery } from '@/parsec/shamir';
import { Information, InformationLevel, InformationManager, PresentationMode } from '@/services/informationManager';
Expand Down
10 changes: 10 additions & 0 deletions client/src/components/shamir/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS

export enum ShamirTab {
Self = 'shamir-tab-self',
Others = 'shamir-tab-others',
}

export enum ShamirAction {
Greet = 'shamir-action-greet',
}
3 changes: 3 additions & 0 deletions client/src/locales/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,9 @@
},
"lostDevice": "Lost your access?",
"recoverDevice": "Recover my session",
"shamir": {
"invalidLink": "Not a valid recovery link."
},
"organizationRequest": {
"notAvailable": "Requests to join an organization using a certificate is not yet supported on your system.",
"title": "Pending requests",
Expand Down
3 changes: 3 additions & 0 deletions client/src/locales/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -350,6 +350,9 @@
},
"lostDevice": "Vous avez perdu votre accès ?",
"recoverDevice": "Récupérer ma session",
"shamir": {
"invalidLink": "Pas un lien de récupération valide."
},
"organizationRequest": {
"notAvailable": "Les requêtes pour rejoindre une organisation en utilisant un certificat ne sont pas encore disponibles sur votre système.",
"title": "Demandes en attente",
Expand Down
7 changes: 6 additions & 1 deletion client/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import LongPathsSupportModal from '@/views/about/LongPathsSupportModal.vue';
import IncompatibleEnvironmentModal from '@/views/home/IncompatibleEnvironmentModal.vue';
import { Answer, I18n, Locale, MegaSharkPlugin, Obj, StripeConfig, ThemeManager, askQuestion } from 'megashark-lib';

(window as any).DEV_TESTBED_TEMPLATE = 'shamir';

enum AppState {
Ready = 'ready',
Initializing = 'initializing',
Expand Down Expand Up @@ -474,7 +476,10 @@ async function setupApp(): Promise<void> {
window.nativeAPI.log('debug', msg);

// Dev mode, provide a default testbed
const configResult = await libparsec.testNewTestbed('coolorg', import.meta.env.PARSEC_APP_TESTBED_SERVER);
const configResult = await libparsec.testNewTestbed(
(window as any).DEV_TESTBED_TEMPLATE ?? 'coolorg',
import.meta.env.PARSEC_APP_TESTBED_SERVER,
);
if (configResult.ok) {
nextStage(configResult.value); // Fire-and-forget call
} else {
Expand Down
7 changes: 7 additions & 0 deletions client/src/parsec/invitation.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
// Parsec Cloud (https://parsec.cloud) Copyright (c) BUSL-1.1 2016-present Scille SAS

import { getClientConfig } from '@/parsec/internals';
import { getClientInfo } from '@/parsec/login';
import {
AccessToken,
AnyClaimRetrievedInfo,
ClaimerRetrieveInfoError,
ClientCancelInvitationError,
ClientInfo,
ClientNewUserInvitationError,
Expand Down Expand Up @@ -90,3 +93,7 @@ export async function cancelInvitation(token: AccessToken): Promise<Result<null,
}
return generateNoHandleError<ClientCancelInvitationError>();
}

export async function retrieveInvitationInfo(link: string): Promise<Result<AnyClaimRetrievedInfo, ClaimerRetrieveInfoError>> {
return await libparsec.claimerRetrieveInfo(getClientConfig(), link);
}
Loading
Loading