Radish alpha
r
Radicle web interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
Improve loading and edge cases
Sebastian Martinez committed 4 years ago
commit 6d5d508220008db73ebb9d2e76c2e9438e3d3e46
parent 5ef2b7512cd1d9d9f754bc21904a77690424d1e7
4 files changed +76 -31
added src/SiweConnect.svelte
@@ -0,0 +1,34 @@
+
<script lang="ts">
+
  import type { Seed } from "@app/base/seeds/Seed";
+
  import type { Config } from "@app/config";
+
  import { signInWithEthereum } from "@app/siwe";
+
  import Loading from "@app/Loading.svelte";
+
  import { Connection } from "@app/session";
+

+
  export let seed: Seed;
+
  export let config: Config;
+
  export let caption = "Sign in with Ethereum";
+

+
  let connection: Connection = Connection.Disconnected;
+
</script>
+

+
<style>
+
  button {
+
    min-height: 32px;
+
  }
+
</style>
+

+
<button
+
  class="tiny secondary"
+
  disabled={connection === Connection.Connecting}
+
  on:click={async () => {
+
    connection = Connection.Connecting;
+
    await signInWithEthereum(seed, config);
+
  }}
+
>
+
  {#if connection === Connection.Connecting}
+
    <Loading small />
+
  {:else}
+
    {caption}
+
  {/if}
+
</button>
modified src/base/seeds/View.svelte
@@ -7,26 +7,23 @@
  import NotFound from "@app/NotFound.svelte";
  import Clipboard from "@app/Clipboard.svelte";
  import Projects from "@app/base/orgs/View/Projects.svelte";
-
  import { SeedSession, signInWithEthereum } from "@app/siwe";
  import { session } from "@app/session";
  import Address from "@app/Address.svelte";
+
  import SiweConnect from "@app/SiweConnect.svelte";
+
  import type { SeedSession } from "@app/siwe";

  export let config: Config;
  export let host: string;

-
  let sessionData: SeedSession | null = null;
+
  let siweSession: SeedSession | null = null;

-
  $: if ($session) {
+
  $: if ($session?.siwe) {
    const entries = Object.entries($session.siwe);
    const result = entries.find(([, session]) => session.domain === host);
    if (result) {
-
      sessionData = result[1];
+
      siweSession = result[1];
    }
  }
-

-
  const signIn = async (seed: Seed) => {
-
    await signInWithEthereum(seed, config);
-
  };
</script>

<style>
@@ -124,20 +121,26 @@
      <div class="desktop" />
      <!-- User Session -->
      <div class="label">Connection</div>
-
      {#if sessionData}
-
        <div class="desktop"><Address address={sessionData.address} resolve {config} /></div>
-
        <div class="mobile"><Address address={sessionData.address} compact resolve {config} /></div>
-
        <div class="desktop" />
-
      {:else}
-
        <div class="subtle">Not connected</div>
-
        {#if config.signer}
-
          <div class="desktop">
-
            <button class="tiny secondary" on:click={() => signIn(seed)}>
-
              Sign in with Ethereum
-
            </button>
-
          </div>
+
      <div>
+
        {#if $session?.signer}
+
          {#if siweSession}
+
            <div class="desktop">
+
              <Address address={siweSession.address} {config} resolve />
+
            </div>
+
            <div class="mobile">
+
              <Address address={siweSession.address} {config} compact resolve />
+
            </div>
+
          {:else}
+
            <SiweConnect
+
              {seed}
+
              {config}
+
            />
+
          {/if}
+
        {:else}
+
          <div class="subtle">Please connect your wallet.</div>
        {/if}
-
      {/if}
+
      </div>
+
      <div class="desktop" />
    </div>
    <!-- Seed Projects -->
    <Projects {seed} {config} />
modified src/session.ts
@@ -8,6 +8,7 @@ import type { TypedDataSigner } from '@ethersproject/abstract-signer';
import type { WalletConnectSigner } from "./WalletConnectSigner";
import * as ethers from "ethers";
import type { SeedSession } from "./siwe";
+
import { unixTime } from "./utils";

export enum Connection {
  Disconnected,
@@ -310,8 +311,11 @@ export function loadSeedSessions(): { [key: string]: SeedSession } {
  if (siweStorage) {
    const siwe: { [key: string]: SeedSession } = JSON.parse(siweStorage);

-
    // We only keep the sessions that are still valid and remove expired from localStorage
-
    const activeSessions = Object.fromEntries(Object.entries(siwe).filter(([, value]) => value.expiration_time > Date.now() / 1000));
+
    // We only keep the sessions that are still valid, and remove expired ones from `localStorage`.
+
    // For a session to be valid the expiration time has to be bigger or equal than the current time.
+
    const activeSessions = Object.fromEntries(Object.entries(siwe).filter(([, value]) => {
+
      return value.expiration_time >= unixTime();
+
    }));
    window.localStorage.setItem("siwe", JSON.stringify({ ...activeSessions }));

    return activeSessions;
@@ -358,5 +362,5 @@ function saveSession(session: Session): void {
  const { address, tokenBalance, tx, siwe } = session;

  window.localStorage.setItem("metamask", JSON.stringify({ address, tokenBalance, tx }));
-
  window.localStorage.setItem("siwe", JSON.stringify({ ...siwe }));
+
  window.localStorage.setItem("siwe", JSON.stringify(siwe));
}
modified src/siwe.ts
@@ -3,8 +3,8 @@ import { SiweMessage } from "siwe";
import { Request, type Host } from '@app/api';
import type { Config } from "@app/config";
import { removePrefix } from "@app/utils";
-
import { connectSeed } from "./session";
-
import type { Seed } from "./base/seeds/Seed";
+
import { connectSeed } from "@app/session";
+
import type { Seed } from "@app/base/seeds/Seed";

export interface SeedSession {
  domain: string;
@@ -20,8 +20,8 @@ export interface SeedSession {
}

export function createSiweMessage(seed: Seed, address: string, nonce: string, config: Config): string {
-
  const date = new Date();
-
  const expirationTime = new Date(date.getFullYear(), date.getMonth(), date.getDate() + 7).toISOString();
+
  const nextWeek = new Date();
+
  nextWeek.setDate(nextWeek.getDate() + 7);

  const message = new SiweMessage({
    domain: seed.api.host,
@@ -30,8 +30,7 @@ export function createSiweMessage(seed: Seed, address: string, nonce: string, co
    uri: window.location.origin,
    nonce,
    version: '1',
-
    resources: [`rad:git:${seed.id}`],
-
    expirationTime,
+
    expirationTime: nextWeek.toISOString(),
    chainId: config.network.chainId
  });

@@ -53,7 +52,12 @@ export async function signInWithEthereum(seed: Seed, config: Config): Promise<{
  const message = createSiweMessage(seed, address, result.nonce, config);
  const signature = await config.signer.signMessage(message);

-
  const auth: { id: string; session: SeedSession } = await new Request(`sessions/${result.id}`, seed.api).put({ message, signature: removePrefix(signature) });
+
  const auth: {
+
    id: string;
+
    session: SeedSession;
+
  } = await new Request(`sessions/${result.id}`, seed.api)
+
    .put({ message, signature: removePrefix(signature) });
+

  connectSeed({ id: result.id, session: auth.session });

  return { id: result.id };