Skip to content

Commit

Permalink
Revamp of twitter stamp updating verification credentials
Browse files Browse the repository at this point in the history
1402 revamp of twitter stamp updating verification credentials
  • Loading branch information
aminah-io authored Jul 14, 2023
2 parents d64189e + 685ff1e commit d1b9abb
Show file tree
Hide file tree
Showing 25 changed files with 748 additions and 141 deletions.
5 changes: 3 additions & 2 deletions app/.env-example.env
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ NEXT_PUBLIC_PASSPORT_GOOGLE_CLIENT_ID=MY-APP-ID.apps.googleusercontent.com
NEXT_PUBLIC_PASSPORT_GOOGLE_CALLBACK=http://localhost:3000/

NEXT_PUBLIC_PASSPORT_TWITTER_CLIENT_ID=ABC123456789
NEXT_PUBLIC_PASSPORT_TWITTER_CALLBACK=http://localhost:3000/
NEXT_PUBLIC_PASSPORT_TWITTER_CALLBACK=http://127.0.0.1:3000/
NEXT_PUBLIC_PASSPORT_FACEBOOK_APP_ID=123456789
NEXT_PUBLIC_PASSPORT_GITHUB_CLIENT_ID=12345678
NEXT_PUBLIC_PASSPORT_GITHUB_CALLBACK=http://localhost:3000/
Expand All @@ -21,7 +21,7 @@ NEXT_PUBLIC_PASSPORT_SIGNER_URL=http://localhost:8000/

NEXT_PUBLIC_PASSPORT_IAM_URL=http://localhost:8003/api/
NEXT_PUBLIC_PASSPORT_IAM_ISSUER_DID=did:key:z6MkghvGHLobLEdj1bgRLhS4LPGJAvbMA1tn2zcRyqmYU5LC
NEXT_PUBLIC_PASSPORT_PROCEDURE_URL=http://localhost:80/procedure/
NEXT_PUBLIC_PASSPORT_PROCEDURE_URL=http://localhost:8003/procedure/

NEXT_PUBLIC_PASSPORT_MAINNET_RPC_URL=YOUR_RPC_URL
NEXT_PUBLIC_PASSPORT_SEPOLIA_RPC_URL=YOUR_RPC_URL
Expand All @@ -44,6 +44,7 @@ NEXT_PUBLIC_FF_HOLONYM_STAMP=on
NEXT_PUBLIC_FF_NEW_GITHUB_STAMPS=on
NEXT_PUBLIC_FF_ONE_CLICK_VERIFICATION=on
NEXT_PUBLIC_FF_LIVE_ALLO_SCORE=on
NEXT_PUBLIC_FF_NEW_TWITTER_STAMPS=on

NEXT_PUBLIC_CERAMIC_CACHE_ENDPOINT=http://localhost:8002/

Expand Down
24 changes: 24 additions & 0 deletions app/__test-fixtures__/contextTestHelpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,30 @@ export const makeTestCeramicContext = (initialState?: Partial<CeramicContextStat
providerSpec: getProviderSpec("Twitter", "TwitterTweetGT10"),
stamp: undefined,
},
"twitterAccountAgeGte#180": {
providerSpec: getProviderSpec("Twitter", "twitterAccountAgeGte#180"),
stamp: undefined,
},
"twitterAccountAgeGte#365": {
providerSpec: getProviderSpec("Twitter", "twitterAccountAgeGte#365"),
stamp: undefined,
},
"twitterAccountAgeGte#730": {
providerSpec: getProviderSpec("Twitter", "twitterAccountAgeGte#730"),
stamp: undefined,
},
"twitterTweetDaysGte#30": {
providerSpec: getProviderSpec("Twitter", "twitterTweetDaysGte#30"),
stamp: undefined,
},
"twitterTweetDaysGte#60": {
providerSpec: getProviderSpec("Twitter", "twitterTweetDaysGte#60"),
stamp: undefined,
},
"twitterTweetDaysGte#120": {
providerSpec: getProviderSpec("Twitter", "twitterTweetDaysGte#120"),
stamp: undefined,
},
POAP: {
providerSpec: getProviderSpec("POAP", "POAP"),
stamp: undefined,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";
import { screen, fireEvent } from "@testing-library/react";
import { TwitterPlatform } from "../../../components/PlatformCards";

import { UserContextState } from "../../../context/userContext";
import { STAMP_PROVIDERS } from "../../../config/providers";
Expand Down
3 changes: 2 additions & 1 deletion iam/.env-example.env
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,5 @@ PASSPORT_STAMP_METADATA_PATH=http://localhost:3000/stampMetadata.json

# Use this environment variable to enable/disable testnets on on-chain-based stamp evaluation.
INCLUDE_TESTNETS=false
ZKSYNC_ERA_MAINNET_ENDPOINT=zksync_mainnet_endpoint
ZKSYNC_ERA_MAINNET_ENDPOINT=zksync_mainnet_endpoint
FF_NEW_TWITTER_STAMPS=on
4 changes: 4 additions & 0 deletions infra/production/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,10 @@ const service = new awsx.ecs.FargateService("dpopp-iam", {
name: "ZKSYNC_ERA_MAINNET_ENDPOINT",
valueFrom: `${IAM_SERVER_SSM_ARN}:ZKSYNC_ERA_MAINNET_ENDPOINT::`,
},
{
name: "FF_NEW_TWITTER_STAMPS",
valueFrom: `${IAM_SERVER_SSM_ARN}:FF_NEW_TWITTER_STAMPS::`,
},
],
},
},
Expand Down
4 changes: 4 additions & 0 deletions infra/review/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,10 @@ const service = new awsx.ecs.FargateService("dpopp-iam", {
name: "ZKSYNC_ERA_MAINNET_ENDPOINT",
valueFrom: `${IAM_SERVER_SSM_ARN}:ZKSYNC_ERA_MAINNET_ENDPOINT::`,
},
{
name: "FF_NEW_TWITTER_STAMPS",
valueFrom: `${IAM_SERVER_SSM_ARN}:FF_NEW_TWITTER_STAMPS::`,
},
],
},
},
Expand Down
4 changes: 4 additions & 0 deletions infra/staging/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ const service = new awsx.ecs.FargateService("dpopp-iam", {
name: "ZKSYNC_ERA_MAINNET_ENDPOINT",
valueFrom: `${IAM_SERVER_SSM_ARN}:ZKSYNC_ERA_MAINNET_ENDPOINT::`,
},
{
name: "FF_NEW_TWITTER_STAMPS",
valueFrom: `${IAM_SERVER_SSM_ARN}:FF_NEW_TWITTER_STAMPS::`,
},
],
},
},
Expand Down
14 changes: 5 additions & 9 deletions platforms/src/ClearText/Providers/clearTextTwitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import type { RequestPayload, VerifiedPayload } from "@gitcoin/passport-types";
// ----- Twitters OAuth2 library
import {
getAuthClient,
requestFindMyUser,
getTwitterUserData,
TwitterContext,
TwitterFindMyUserResponse,
TwitterUserData,
} from "../../Twitter/procedures/twitterOauth";
import type { Provider, ProviderOptions } from "../../types";
// import { verifyTwitter } from "../providers/twitter";
Expand All @@ -26,7 +26,7 @@ export class ClearTextTwitterProvider implements Provider {
// verify that the proof object contains valid === "true"
async verify(payload: RequestPayload, context: TwitterContext): Promise<VerifiedPayload> {
let valid = false,
verifiedPayload: TwitterFindMyUserResponse = {},
verifiedPayload: TwitterUserData = {},
pii;

try {
Expand All @@ -47,13 +47,9 @@ export class ClearTextTwitterProvider implements Provider {
}
}

async function verifyUserTwitter(
sessionKey: string,
code: string,
context: TwitterContext
): Promise<TwitterFindMyUserResponse> {
async function verifyUserTwitter(sessionKey: string, code: string, context: TwitterContext): Promise<TwitterUserData> {
const twitterClient = await getAuthClient(sessionKey, code, context);
const myUser = await requestFindMyUser(twitterClient);
const myUser = await getTwitterUserData(context, twitterClient);

return myUser;
}
21 changes: 10 additions & 11 deletions platforms/src/ClearText/__tests__/clearTextTwitter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,17 @@ import { ClearTextTwitterProvider } from "../Providers/clearTextTwitter";

import { RequestPayload } from "@gitcoin/passport-types";
import { auth, Client } from "twitter-api-sdk";
import { getAuthClient, requestFindMyUser, TwitterFindMyUserResponse } from "../../Twitter/procedures/twitterOauth";
import { getAuthClient, getTwitterUserData, TwitterUserData } from "../../Twitter/procedures/twitterOauth";

jest.mock("../../Twitter/procedures/twitterOauth", () => ({
getAuthClient: jest.fn(),
requestFindMyUser: jest.fn(),
getTwitterUserData: jest.fn(),
}));

const MOCK_TWITTER_CLIENT = new Client({} as auth.OAuth2User);

const MOCK_TWITTER_USER: TwitterFindMyUserResponse = {
const MOCK_TWITTER_USER: TwitterUserData = {
id: "123",
name: "Userguy McTesterson",
username: "DpoppDev",
};

Expand All @@ -30,7 +29,7 @@ beforeEach(() => {

describe("Attempt verification", function () {
it("handles valid verification attempt", async () => {
(requestFindMyUser as jest.Mock).mockResolvedValue(MOCK_TWITTER_USER);
(getTwitterUserData as jest.Mock).mockResolvedValue(MOCK_TWITTER_USER);

const twitter = new ClearTextTwitterProvider();
const verifiedPayload = await twitter.verify(
Expand All @@ -44,7 +43,7 @@ describe("Attempt verification", function () {
);

expect(getAuthClient).toBeCalledWith(sessionKey, code, {});
expect(requestFindMyUser).toBeCalled();
expect(getTwitterUserData).toBeCalled();
expect(verifiedPayload).toEqual({
valid: true,
record: {
Expand All @@ -53,8 +52,8 @@ describe("Attempt verification", function () {
});
});

it("should return invalid payload when there is no username in requestFindMyUser response", async () => {
(requestFindMyUser as jest.Mock).mockResolvedValue({ username: undefined } as TwitterFindMyUserResponse);
it("should return invalid payload when there is no username in getTwitterUserData response", async () => {
(getTwitterUserData as jest.Mock).mockResolvedValue({ username: undefined } as TwitterUserData);

const twitter = new ClearTextTwitterProvider();

Expand All @@ -71,8 +70,8 @@ describe("Attempt verification", function () {
expect(verifiedPayload).toMatchObject({ valid: false });
});

it("should return invalid payload when requestFindMyUser throws", async () => {
(requestFindMyUser as jest.Mock).mockRejectedValue("unauthorized");
it("should return invalid payload when getTwitterUserData throws", async () => {
(getTwitterUserData as jest.Mock).mockRejectedValue("unauthorized");

const twitter = new ClearTextTwitterProvider();

Expand All @@ -91,7 +90,7 @@ describe("Attempt verification", function () {

it("should return invalid payload when unable to retrieve twitter oauth client", async () => {
(getAuthClient as jest.Mock).mockRejectedValue("unauthorized");
(requestFindMyUser as jest.Mock).mockImplementationOnce(async (client) => {
(getTwitterUserData as jest.Mock).mockImplementationOnce(async (client) => {
return client ? MOCK_TWITTER_USER : {};
});

Expand Down
146 changes: 102 additions & 44 deletions platforms/src/Twitter/Providers-config.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,7 @@
import { PlatformSpec, PlatformGroupSpec, Provider } from "../types";
import TwitterAuthProvider from "./Providers/TwitterAuthProvider";
import {
TwitterFollowerGT100Provider,
TwitterFollowerGT500Provider,
TwitterFollowerGTE1000Provider,
TwitterFollowerGT5000Provider,
} from "./Providers/TwitterFollowerProvider";
import { TwitterTweetGT10Provider } from "./Providers/TwitterTweetsProvider";
import { TwitterAccountAgeProvider } from "./Providers/twitterAccountAge";
import { TwitterTweetDaysProvider } from "./Providers/twitterTweetDays";
import * as legacyProviders from "./Providers/legacy";

export const PlatformDetails: PlatformSpec = {
icon: "./assets/twitterStampIcon.svg",
Expand All @@ -16,40 +11,103 @@ export const PlatformDetails: PlatformSpec = {
connectMessage: "Connect Account",
};

export const ProviderConfig: PlatformGroupSpec[] = [
{
platformGroup: "Account Name",
providers: [{ title: "Encrypted", name: "Twitter" }],
},
{
platformGroup: "Tweet/Posts",
providers: [{ title: "More than 10", name: "TwitterTweetGT10" }],
},
{
platformGroup: "Followers",
providers: [
{ title: "More than 100", name: "TwitterFollowerGT100" },
{
title: "More than 500",
name: "TwitterFollowerGT500",
},
{
title: "More than 1000",
name: "TwitterFollowerGTE1000",
},
{
title: "More than 5000",
name: "TwitterFollowerGT5000",
},
],
},
];
let providers: Provider[] = [];
let ProviderConfig: PlatformGroupSpec[] = [];

export const providers: Provider[] = [
new TwitterAuthProvider(),
new TwitterTweetGT10Provider(),
new TwitterFollowerGT100Provider(),
new TwitterFollowerGT500Provider(),
new TwitterFollowerGTE1000Provider(),
new TwitterFollowerGT5000Provider(),
];
if (process.env.FF_NEW_TWITTER_STAMPS === "on" || process.env.NEXT_PUBLIC_FF_NEW_TWITTER_STAMPS === "on") {
ProviderConfig = [
{
platformGroup: "Account Creation",
providers: [
{
title: "Created at least 180 days ago",
name: "twitterAccountAgeGte#180",
},
{
title: "Created at least 1 year ago",
name: "twitterAccountAgeGte#365",
},
{
title: "Created at least 2 years ago",
name: "twitterAccountAgeGte#730",
},
],
},
{
platformGroup: "Consistent Engagement",
providers: [
{
title: "Tweet on at least 30 distinct days",
name: "twitterTweetDaysGte#30",
},
{
title: "Tweets on at least 60 distinct days",
name: "twitterTweetDaysGte#60",
},
{
title: "Tweets on at least 120 distinct days",
name: "twitterTweetDaysGte#120",
},
],
},
];
providers = [
new TwitterAccountAgeProvider({
threshold: "180",
}),
new TwitterAccountAgeProvider({
threshold: "365",
}),
new TwitterAccountAgeProvider({
threshold: "730",
}),
new TwitterTweetDaysProvider({
threshold: "30",
}),
new TwitterTweetDaysProvider({
threshold: "60",
}),
new TwitterTweetDaysProvider({
threshold: "120",
}),
];
} else {
ProviderConfig = [
{
platformGroup: "Account Name",
providers: [{ title: "Encrypted", name: "Twitter" }],
},
{
platformGroup: "Tweet/Posts",
providers: [{ title: "More than 10", name: "TwitterTweetGT10" }],
},
{
platformGroup: "Followers",
providers: [
{ title: "More than 100", name: "TwitterFollowerGT100" },
{
title: "More than 500",
name: "TwitterFollowerGT500",
},
{
title: "More than 1000",
name: "TwitterFollowerGTE1000",
},
{
title: "More than 5000",
name: "TwitterFollowerGT5000",
},
],
},
];
providers = [
new legacyProviders.TwitterProvider(),
new legacyProviders.TwitterTweetGT10Provider(),
new legacyProviders.TwitterFollowerGT100Provider(),
new legacyProviders.TwitterFollowerGT500Provider(),
new legacyProviders.TwitterFollowerGTE1000Provider(),
new legacyProviders.TwitterFollowerGT5000Provider(),
];
}

export { providers, ProviderConfig };
Loading

0 comments on commit d1b9abb

Please sign in to comment.