Skip to content

Commit

Permalink
fix(app): filter out expired stamps from provider state (#1576)
Browse files Browse the repository at this point in the history
* fix(app): filter out expired stamps from provider state

* fix(app): use provider from stamp mock
  • Loading branch information
schultztimothy authored Aug 10, 2023
1 parent 5d74cda commit a5942d8
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 30 deletions.
65 changes: 64 additions & 1 deletion app/__tests__/context/ceramicContext.test.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { render, waitFor, screen, waitForElementToBeRemoved, fireEvent } from "@testing-library/react";
import { useContext, useState, useEffect } from "react";
import { CeramicContext, CeramicContextProvider, CeramicContextState } from "../../context/ceramicContext";
import {
AllProvidersState,
CeramicContext,
CeramicContextProvider,
CeramicContextState,
cleanPassport,
} from "../../context/ceramicContext";
import { CeramicDatabase, PassportDatabase } from "@gitcoin/passport-database-client";
import {
googleStampFixture,
Expand All @@ -10,6 +16,7 @@ import {
} from "../../__test-fixtures__/databaseStorageFixtures";
import { makeTestUserContext } from "../../__test-fixtures__/contextTestHelpers";
import { UserContext, UserContextState } from "../../context/userContext";
import { Passport } from "@gitcoin/passport-types";

const mockUserContext: UserContextState = makeTestUserContext();

Expand Down Expand Up @@ -51,6 +58,7 @@ const stamps = [googleStampFixture, discordStampFixture, brightidStampFixture, f
stamp.credential.expirationDate = "2099-05-15T21:04:01.708Z";
stamp.credential.credentialSubject.id = "test-user-did";
stamp.credential.issuer = process.env.NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID || "";
stamp.credential.credentialSubject.provider = stamp.provider;
return stamp;
});

Expand Down Expand Up @@ -439,3 +447,58 @@ describe("CeramicContextProvider syncs stamp state with ceramic", () => {
}
});
});

const userDid = "test-user-did";
const mockDatabase = {
did: userDid,
} as PassportDatabase;
const mockProvidersState = {
google: true,
facebook: true,
} as AllProvidersState;

describe("cleanPassport function", () => {
it("removes expired stamps", () => {
const expiredStamp = {
credential: {
expirationDate: "2000-05-15T21:04:01.708Z",
credentialSubject: { provider: "google", id: "test-user-did" },
issuer: process.env.NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID || "",
},
};

const passport = { stamps: [expiredStamp] } as Passport;
const result = cleanPassport(passport, mockDatabase, mockProvidersState);
expect(result.passport.stamps).toHaveLength(0);
expect(result.expiredProviders).toContain("google");
});

it("keeps valid stamps", () => {
const validStamp = {
credential: {
expirationDate: "2099-05-15T21:04:01.708Z",
credentialSubject: { provider: "facebook", id: "test-user-did" },
issuer: process.env.NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID || "",
},
};

const passport = { stamps: [validStamp] } as Passport;
const result = cleanPassport(passport, mockDatabase, mockProvidersState);
expect(result.passport.stamps.length).toBe(1);
expect(result.expiredProviders.length).toBe(0);
});
it("filters out stamps that aren't in the providers state", () => {
const validStamp = {
credential: {
expirationDate: "2099-05-15T21:04:01.708Z",
credentialSubject: { provider: "poap", id: "test-user-did" },
issuer: process.env.NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID || "",
},
};

const passport = { stamps: [validStamp] } as Passport;
const result = cleanPassport(passport, mockDatabase, mockProvidersState);
expect(result.passport.stamps.length).toBe(0);
expect(result.expiredProviders.length).toBe(0);
});
});
71 changes: 42 additions & 29 deletions app/context/ceramicContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,43 @@ const CERAMIC_TIMEOUT_MS = process.env.CERAMIC_TIMEOUT_MS || "10000";

export const CeramicContext = createContext(startingState);

export const cleanPassport = (
passport: Passport,
database: CeramicDatabase | PassportDatabase,
allProvidersState: AllProvidersState
): {
passport: Passport;
expiredProviders: PROVIDER_ID[];
} => {
const tempExpiredProviders: PROVIDER_ID[] = [];
const currentProviderIds = Object.keys(allProvidersState);
// clean stamp content if expired or from a different issuer
if (passport) {
passport.stamps = passport.stamps.filter((stamp: Stamp) => {
if (stamp) {
const providerId = stamp.credential.credentialSubject.provider as PROVIDER_ID;
if (!currentProviderIds.includes(providerId)) {
return false;
}

const has_expired = new Date(stamp.credential.expirationDate) < new Date();
if (has_expired) {
tempExpiredProviders.push(providerId);
}

const has_correct_issuer = stamp.credential.issuer === IAM_ISSUER_DID;
const has_correct_subject = stamp.credential.credentialSubject.id.toLowerCase() === database.did;

return !has_expired && has_correct_issuer && has_correct_subject;
} else {
return false;
}
});
}

return { passport, expiredProviders: tempExpiredProviders };
};

export const CeramicContextProvider = ({ children }: { children: any }) => {
const [allProvidersState, setAllProviderState] = useState(startingAllProvidersState);
const resolveCancel = useRef<() => void>();
Expand Down Expand Up @@ -377,7 +414,11 @@ export const CeramicContextProvider = ({ children }: { children: any }) => {
passport?: Passport,
skipLoadingState?: boolean
): Passport => {
const cleanedPassport = cleanPassport(passport, database) as Passport;
if (!passport) {
passport = { stamps: [] };
}
const { passport: cleanedPassport, expiredProviders } = cleanPassport(passport, database, allProvidersState);
setExpiredProviders(expiredProviders);
hydrateAllProvidersState(cleanedPassport);
setPassport(cleanedPassport);
if (!skipLoadingState) setIsLoadingPassport(IsLoadingPassportState.Idle);
Expand Down Expand Up @@ -438,34 +479,6 @@ export const CeramicContextProvider = ({ children }: { children: any }) => {
return passportToReturn;
};

const cleanPassport = (
passport: Passport | undefined | false,
database: CeramicDatabase | PassportDatabase
): Passport | undefined | false => {
const tempExpiredProviders: PROVIDER_ID[] = [];
// clean stamp content if expired or from a different issuer
if (passport) {
passport.stamps = passport.stamps.filter((stamp: Stamp) => {
if (stamp) {
const has_expired = new Date(stamp.credential.expirationDate) < new Date();
if (has_expired) {
tempExpiredProviders.push(stamp.credential.credentialSubject.provider as PROVIDER_ID);
}

const has_correct_issuer = stamp.credential.issuer === IAM_ISSUER_DID;
const has_correct_subject = stamp.credential.credentialSubject.id.toLowerCase() === database.did;

return !has_expired && has_correct_issuer && has_correct_subject;
} else {
return false;
}
});
setExpiredProviders(tempExpiredProviders);
}

return passport;
};

const handleCheckRefreshPassport = async (): Promise<boolean> => {
let success = true;
if (ceramicClient && passportLoadResponse) {
Expand Down

0 comments on commit a5942d8

Please sign in to comment.