Skip to content

Commit

Permalink
Credentials (#4558)
Browse files Browse the repository at this point in the history
  • Loading branch information
julianjelfs authored Oct 12, 2023
1 parent ec3ab40 commit cb209d8
Show file tree
Hide file tree
Showing 52 changed files with 828 additions and 289 deletions.
7 changes: 6 additions & 1 deletion backend/libraries/gated_groups/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use candid::Principal;
use sns_governance_canister::types::neuron::DissolveState;
use sns_governance_canister::types::Neuron;
use types::{AccessGate, CanisterId, GateCheckFailedReason, SnsNeuronGate, UserId};
use types::{AccessGate, CanisterId, GateCheckFailedReason, SnsNeuronGate, UserId, VerifiedCredentialGate};
use user_index_canister_c2c_client::LookupUserError;

pub enum CheckIfPassesGateResult {
Expand All @@ -16,6 +16,7 @@ pub async fn check_if_passes_gate(
user_index_canister_id: CanisterId,
) -> CheckIfPassesGateResult {
match gate {
AccessGate::VerifiedCredential(g) => check_verified_credential_gate(g, user_id).await,
AccessGate::DiamondMember => check_diamond_member_gate(user_id, user_index_canister_id).await,
AccessGate::SnsNeuron(g) => check_sns_neuron_gate(g, user_id).await,
}
Expand All @@ -35,6 +36,10 @@ async fn check_diamond_member_gate(user_id: UserId, user_index_canister_id: Cani
}
}

async fn check_verified_credential_gate(_gate: &VerifiedCredentialGate, _user_id: UserId) -> CheckIfPassesGateResult {
CheckIfPassesGateResult::Success
}

async fn check_sns_neuron_gate(gate: &SnsNeuronGate, user_id: UserId) -> CheckIfPassesGateResult {
let args = sns_governance_canister::list_neurons::Args {
limit: 10,
Expand Down
6 changes: 6 additions & 0 deletions backend/libraries/types/can.did
Original file line number Diff line number Diff line change
Expand Up @@ -1382,6 +1382,7 @@ type DiamondMembershipPlanDuration = variant {

type AccessGate = variant {
DiamondMember;
VerifiedCredential: VerifiedCredentialGate;
SnsNeuron : SnsNeuronGate;
};

Expand All @@ -1396,6 +1397,11 @@ type GroupGateUpdated = record {
new_gate : opt AccessGate;
};

type VerifiedCredentialGate = record {
issuer: text;
credential: text;
};

type SnsNeuronGate = record {
governance_canister_id : CanisterId;
min_stake_e8s : opt nat64;
Expand Down
7 changes: 7 additions & 0 deletions backend/libraries/types/src/gated_groups.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,16 @@ use serde::{Deserialize, Serialize};
#[derive(CandidType, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
pub enum AccessGate {
DiamondMember,
VerifiedCredential(VerifiedCredentialGate),
SnsNeuron(SnsNeuronGate),
}

#[derive(CandidType, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
pub struct VerifiedCredentialGate {
pub issuer: String,
pub credential: String,
}

#[derive(CandidType, Serialize, Deserialize, Clone, Debug, Eq, PartialEq)]
pub struct SnsNeuronGate {
pub governance_canister_id: CanisterId,
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/components/Select.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import { rtlStore } from "../stores/rtl";
import MenuDown from "svelte-material-icons/MenuDown.svelte";
export let value: unknown = "";
export let value: unknown;
export let invalid: boolean = false;
export let disabled: boolean = false;
export let margin: boolean = true;
Expand Down
38 changes: 20 additions & 18 deletions frontend/app/src/components/home/AccessGateIcon.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,21 @@
import { _ } from "svelte-i18n";
import TooltipWrapper from "../TooltipWrapper.svelte";
import TooltipPopup from "../TooltipPopup.svelte";
import { E8S_PER_TOKEN, type AccessGate, isSnsGate } from "openchat-client";
import { createEventDispatcher } from "svelte";
import { E8S_PER_TOKEN, type AccessGate, isSnsGate, OpenChat } from "openchat-client";
import { createEventDispatcher, getContext } from "svelte";
import type { Alignment, Position } from "../../utils/alignment";
import { snsGateBindings } from "../../utils/access";
export let gate: AccessGate;
export let position: Position = "top";
export let align: Alignment = "start";
export let small = false;
const client = getContext<OpenChat>("client");
const dispatch = createEventDispatcher();
$: params = formatParams(gate);
$: cryptoLookup = client.cryptoLookup;
$: tokenDetails = client.getTokenDetailsForSnsAccessGate(gate, $cryptoLookup);
function formatParams(gate: AccessGate): string {
const parts = [];
Expand Down Expand Up @@ -46,14 +48,25 @@
</TooltipPopup>
</div>
</TooltipWrapper>
{:else if gate.kind === "credential_gate"}
<TooltipWrapper {position} {align}>
<div slot="target" class="credential">🔒️</div>
<div let:position let:align slot="tooltip">
<TooltipPopup {position} {align}>
{$_("access.credentialGateInfo", {
values: { issuer: gate.issuerOrigin, credential: gate.credentialId },
})}
</TooltipPopup>
</div>
</TooltipWrapper>
{:else if isSnsGate(gate)}
<TooltipWrapper {position} {align}>
<div slot="target" class={`icon ${snsGateBindings[gate.kind].cssClass}`} class:small />
<img slot="target" class="icon" class:small src={tokenDetails?.logo} />
<div let:position let:align slot="tooltip">
<TooltipPopup {position} {align}>
<p>
{`${$_("access.snsHolderInfo", {
values: snsGateBindings[gate.kind].labelParams,
values: tokenDetails ? { token: tokenDetails.symbol } : undefined,
})}`}
</p>
<p class="params">{params}</p>
Expand All @@ -79,22 +92,11 @@
width: 26px;
}
}
.diamond {
.diamond,
.credential {
cursor: pointer;
@include font-size(fs-130);
}
.oc {
background-image: url("/assets/spinner.svg");
}
.sns1 {
background-image: url("/assets/sns1_token.png");
}
.kinic {
background-image: url("/assets/kinic_token.png");
}
.hot {
background-image: url("../assets/hot_token.svg");
}
.params {
margin-top: $sp3;
Expand Down
63 changes: 49 additions & 14 deletions frontend/app/src/components/home/AccessGateParameters.svelte
Original file line number Diff line number Diff line change
@@ -1,28 +1,63 @@
<script lang="ts">
import { _ } from "svelte-i18n";
import { E8S_PER_TOKEN, type SNSAccessGate } from "openchat-client";
import { snsGateBindings } from "../../utils/access";
import {
E8S_PER_TOKEN,
OpenChat,
type CredentialGate,
type SNSAccessGate,
} from "openchat-client";
import { getContext } from "svelte";
export let gate: SNSAccessGate;
const client = getContext<OpenChat>("client");
export let gate: SNSAccessGate | CredentialGate;
$: cryptoLookup = client.cryptoLookup;
$: tokenDetails = client.getTokenDetailsForSnsAccessGate(gate, $cryptoLookup);
</script>

<div class="detail">
<div>{$_("access.snsHolder", { values: snsGateBindings[gate.kind].labelParams })}</div>
<div class="params">
{#if gate.minDissolveDelay}
{#if gate.kind === "credential_gate"}
<div class="detail">
<div>
{$_("access.credential")}
</div>
<div class="params">
<div>
{`${$_("access.minDissolveDelayN", {
values: { n: gate.minDissolveDelay / (24 * 60 * 60 * 1000) },
{`${$_("access.credentialParamIssuer", {
values: { issuer: gate.issuerOrigin },
})}`}
</div>
{/if}
{#if gate.minStakeE8s}
<div>
{`${$_("access.minStakeN", { values: { n: gate.minStakeE8s / E8S_PER_TOKEN } })}`}
{`${$_("access.credentialParamCredential", {
values: { credential: gate.credentialId },
})}`}
</div>
{/if}
</div>
</div>
{:else}
<div class="detail">
<div>
{$_("access.snsHolder", {
values: tokenDetails ? { token: tokenDetails.symbol } : undefined,
})}
</div>
<div class="params">
{#if gate.minDissolveDelay}
<div>
{`${$_("access.minDissolveDelayN", {
values: { n: gate.minDissolveDelay / (24 * 60 * 60 * 1000) },
})}`}
</div>
{/if}
{#if gate.minStakeE8s}
<div>
{`${$_("access.minStakeN", {
values: { n: gate.minStakeE8s / E8S_PER_TOKEN },
})}`}
</div>
{/if}
</div>
</div>
</div>
{/if}

<style lang="scss">
.params {
Expand Down
2 changes: 1 addition & 1 deletion frontend/app/src/components/home/AccessGateSummary.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
<AccessGateIcon {gate} />
{#if gate.kind === "diamond_gate"}
<p>{$_("access.diamondMember")}</p>
{:else if isSnsGate(gate)}
{:else if isSnsGate(gate) || gate.kind === "credential_gate"}
<AccessGateParameters {gate} />
{/if}
</div>
Expand Down
12 changes: 3 additions & 9 deletions frontend/app/src/components/home/ChatMessage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,7 @@
import { _ } from "svelte-i18n";
import { rtlStore } from "../../stores/rtl";
import { now } from "../../stores/time";
import {
createEventDispatcher,
getContext,
onDestroy,
onMount,
tick,
} from "svelte";
import { createEventDispatcher, getContext, onDestroy, onMount, tick } from "svelte";
import { dclickReply } from "../../stores/settings";
import EmoticonLolOutline from "svelte-material-icons/EmoticonLolOutline.svelte";
import Close from "svelte-material-icons/Close.svelte";
Expand Down Expand Up @@ -632,8 +626,8 @@
<style lang="scss">
$size: 10px;
$avatar-width: 56px;
$avatar-width-mob: 43px;
$avatar-width: toRem(56);
$avatar-width-mob: toRem(43);
@media (hover: hover) {
:global(.message-bubble:hover .menu-icon) {
Expand Down
48 changes: 48 additions & 0 deletions frontend/app/src/components/home/CredentialSelector.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<script lang="ts">
import { _ } from "svelte-i18n";
import Legend from "../Legend.svelte";
import Select from "../Select.svelte";
import { credentialIssuers, type CredentialIssuer, type Credential } from "../../utils/access";
import type { CredentialGate } from "openchat-client";
import { onMount } from "svelte";
export let gate: CredentialGate;
let selectedCredentialIssuer: CredentialIssuer;
let selectedCredential: Credential;
onMount(() => {
selectedCredentialIssuer = credentialIssuers[0];
selectedCredential = credentialIssuers[0].credentials[0];
sync();
});
function sync() {
gate.issuerOrigin = selectedCredentialIssuer.value;
gate.credentialId = selectedCredential.value;
}
function issuerChanged() {
selectedCredential = selectedCredentialIssuer.credentials[0];
sync();
}
function credentialChanged() {
sync();
}
</script>

<Legend label={$_("access.credentialIssuer")} />
<Select on:change={issuerChanged} bind:value={selectedCredentialIssuer}>
{#each credentialIssuers as issuer}
<option value={issuer}>{issuer.name}</option>
{/each}
</Select>
{#if selectedCredentialIssuer !== undefined}
<Legend label={$_("access.requiredCredential")} />
<Select on:change={credentialChanged} bind:value={selectedCredential}>
{#each selectedCredentialIssuer.credentials as credential}
<option value={credential}>{credential.name}</option>
{/each}
</Select>
{/if}
6 changes: 3 additions & 3 deletions frontend/app/src/components/home/CurrentChatMessages.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,9 @@
{/if}
{/each}
{#if reverseScroll}
{#if privatePreview}
<PrivatePreview />
{/if}
{#if showAvatar}
{#if $isProposalGroup}
<ProposalBot />
Expand All @@ -375,9 +378,6 @@
</div>
{/if}
{/if}
{#if privatePreview}
<PrivatePreview />
{/if}
{/if}
</ChatEventList>

Expand Down
Loading

0 comments on commit cb209d8

Please sign in to comment.