Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolas Burtey committed Apr 25, 2024
1 parent ac03abc commit b342e0a
Show file tree
Hide file tree
Showing 20 changed files with 312 additions and 46 deletions.
9 changes: 9 additions & 0 deletions apps/consent/app/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,13 @@ export type MerchantPayload = {
readonly merchant?: Maybe<Merchant>;
};

export type MobileSession = {
readonly __typename: 'MobileSession';
readonly expiresAt: Scalars['Timestamp']['output'];
readonly id: Scalars['ID']['output'];
readonly issuedAt: Scalars['Timestamp']['output'];
};

export type MobileVersions = {
readonly __typename: 'MobileVersions';
readonly currentSupported: Scalars['Int']['output'];
Expand Down Expand Up @@ -1921,6 +1928,8 @@ export type User = {
* When value is 'default' the intent is to use preferred language from OS settings.
*/
readonly language: Scalars['Language']['output'];
/** List of mobile sessions */
readonly mobileSessions: ReadonlyArray<MobileSession>;
/** Phone number with international calling code. */
readonly phone?: Maybe<Scalars['Phone']['output']>;
readonly supportChat: ReadonlyArray<SupportMessage>;
Expand Down
20 changes: 20 additions & 0 deletions apps/dashboard/services/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -917,6 +917,13 @@ export type MerchantPayload = {
readonly merchant?: Maybe<Merchant>;
};

export type MobileSession = {
readonly __typename: 'MobileSession';
readonly expiresAt: Scalars['Timestamp']['output'];
readonly id: Scalars['ID']['output'];
readonly issuedAt: Scalars['Timestamp']['output'];
};

export type MobileVersions = {
readonly __typename: 'MobileVersions';
readonly currentSupported: Scalars['Int']['output'];
Expand Down Expand Up @@ -2018,6 +2025,8 @@ export type User = {
* When value is 'default' the intent is to use preferred language from OS settings.
*/
readonly language: Scalars['Language']['output'];
/** List of mobile sessions */
readonly mobileSessions: ReadonlyArray<MobileSession>;
/** Phone number with international calling code. */
readonly phone?: Maybe<Scalars['Phone']['output']>;
readonly statefulNotifications: StatefulNotificationConnection;
Expand Down Expand Up @@ -3525,6 +3534,7 @@ export type ResolversTypes = {
MerchantMapSuggestInput: MerchantMapSuggestInput;
MerchantPayload: ResolverTypeWrapper<MerchantPayload>;
Minutes: ResolverTypeWrapper<Scalars['Minutes']['output']>;
MobileSession: ResolverTypeWrapper<MobileSession>;
MobileVersions: ResolverTypeWrapper<MobileVersions>;
Mutation: ResolverTypeWrapper<{}>;
MyUpdatesPayload: ResolverTypeWrapper<Omit<MyUpdatesPayload, 'update'> & { update?: Maybe<ResolversTypes['UserUpdate']> }>;
Expand Down Expand Up @@ -3750,6 +3760,7 @@ export type ResolversParentTypes = {
MerchantMapSuggestInput: MerchantMapSuggestInput;
MerchantPayload: MerchantPayload;
Minutes: Scalars['Minutes']['output'];
MobileSession: MobileSession;
MobileVersions: MobileVersions;
Mutation: {};
MyUpdatesPayload: Omit<MyUpdatesPayload, 'update'> & { update?: Maybe<ResolversParentTypes['UserUpdate']> };
Expand Down Expand Up @@ -4358,6 +4369,13 @@ export interface MinutesScalarConfig extends GraphQLScalarTypeConfig<ResolversTy
name: 'Minutes';
}

export type MobileSessionResolvers<ContextType = any, ParentType extends ResolversParentTypes['MobileSession'] = ResolversParentTypes['MobileSession']> = {
expiresAt?: Resolver<ResolversTypes['Timestamp'], ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
issuedAt?: Resolver<ResolversTypes['Timestamp'], ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

export type MobileVersionsResolvers<ContextType = any, ParentType extends ResolversParentTypes['MobileVersions'] = ResolversParentTypes['MobileVersions']> = {
currentSupported?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
minSupported?: Resolver<ResolversTypes['Int'], ParentType, ContextType>;
Expand Down Expand Up @@ -4817,6 +4835,7 @@ export type UserResolvers<ContextType = any, ParentType extends ResolversParentT
email?: Resolver<Maybe<ResolversTypes['Email']>, ParentType, ContextType>;
id?: Resolver<ResolversTypes['ID'], ParentType, ContextType>;
language?: Resolver<ResolversTypes['Language'], ParentType, ContextType>;
mobileSessions?: Resolver<ReadonlyArray<ResolversTypes['MobileSession']>, ParentType, ContextType>;
phone?: Resolver<Maybe<ResolversTypes['Phone']>, ParentType, ContextType>;
statefulNotifications?: Resolver<ResolversTypes['StatefulNotificationConnection'], ParentType, ContextType, RequireFields<UserStatefulNotificationsArgs, 'first'>>;
supportChat?: Resolver<ReadonlyArray<ResolversTypes['SupportMessage']>, ParentType, ContextType>;
Expand Down Expand Up @@ -5007,6 +5026,7 @@ export type Resolvers<ContextType = any> = {
Merchant?: MerchantResolvers<ContextType>;
MerchantPayload?: MerchantPayloadResolvers<ContextType>;
Minutes?: GraphQLScalarType;
MobileSession?: MobileSessionResolvers<ContextType>;
MobileVersions?: MobileVersionsResolvers<ContextType>;
Mutation?: MutationResolvers<ContextType>;
MyUpdatesPayload?: MyUpdatesPayloadResolvers<ContextType>;
Expand Down
9 changes: 9 additions & 0 deletions apps/map/services/galoy/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -877,6 +877,13 @@ export type MerchantPayload = {
readonly merchant?: Maybe<Merchant>;
};

export type MobileSession = {
readonly __typename: 'MobileSession';
readonly expiresAt: Scalars['Timestamp']['output'];
readonly id: Scalars['ID']['output'];
readonly issuedAt: Scalars['Timestamp']['output'];
};

export type MobileVersions = {
readonly __typename: 'MobileVersions';
readonly currentSupported: Scalars['Int']['output'];
Expand Down Expand Up @@ -1921,6 +1928,8 @@ export type User = {
* When value is 'default' the intent is to use preferred language from OS settings.
*/
readonly language: Scalars['Language']['output'];
/** List of mobile sessions */
readonly mobileSessions: ReadonlyArray<MobileSession>;
/** Phone number with international calling code. */
readonly phone?: Maybe<Scalars['Phone']['output']>;
readonly supportChat: ReadonlyArray<SupportMessage>;
Expand Down
9 changes: 9 additions & 0 deletions apps/pay/lib/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -876,6 +876,13 @@ export type MerchantPayload = {
readonly merchant?: Maybe<Merchant>;
};

export type MobileSession = {
readonly __typename: 'MobileSession';
readonly expiresAt: Scalars['Timestamp'];
readonly id: Scalars['ID'];
readonly issuedAt: Scalars['Timestamp'];
};

export type MobileVersions = {
readonly __typename: 'MobileVersions';
readonly currentSupported: Scalars['Int'];
Expand Down Expand Up @@ -1920,6 +1927,8 @@ export type User = {
* When value is 'default' the intent is to use preferred language from OS settings.
*/
readonly language: Scalars['Language'];
/** List of mobile sessions */
readonly mobileSessions: ReadonlyArray<MobileSession>;
/** Phone number with international calling code. */
readonly phone?: Maybe<Scalars['Phone']>;
readonly supportChat: ReadonlyArray<SupportMessage>;
Expand Down
14 changes: 14 additions & 0 deletions bats/core/api/user.bats
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ setup_file() {
}

@test "account: updates language" {
"skip"

local new_language="de"

exec_graphql 'alice' 'user-details'
Expand All @@ -25,7 +27,17 @@ setup_file() {
[[ "$language" == "$new_language" ]] || exit 1
}

@test "user: list sessions" {
exec_graphql 'alice' 'list-sessions'
sessions="$(graphql_output '.data.me.mobileSessions')"

echo "$sessions" | jq -e 'all(.[]; has("id") and has("expiresAt"))' > /dev/null
[[ $? -eq 0 ]] || exit 1
}

@test "support: default support message result" {
"skip"

exec_graphql 'alice' 'support-chat'
language="$(graphql_output '.data.me.supportChat')"

Expand All @@ -34,6 +46,8 @@ setup_file() {
}

@test "support: ask 2 questions" {
"skip"

local variables=$(
jq -n \
'{input: {message: "Hello"}}'
Expand Down
11 changes: 11 additions & 0 deletions bats/gql/list-sessions.gql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
query userDetails {
me {
id
phone
mobileSessions {
id
expiresAt
issuedAt
}
}
}
13 changes: 12 additions & 1 deletion bats/helpers/user.bash
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,20 @@ create_user_with_metadata() {
}

random_phone() {
printf "+1%010d\n" $(( ($RANDOM * 1000000) + ($RANDOM % 1000000) ))
# Generate an area code: cannot start with 0 or 1
local area_code=415

# Generate an exchange code: cannot start with 0 or 1
local exchange=$(( $RANDOM % 800 + 200 ))

# Generate a subscriber number: four-digit number
local subscriber=$(( $RANDOM % 10000 ))

# Print formatted phone number
printf "+1%03d%03d%04d\n" $area_code $exchange $subscriber
}


user_update_username() {
local token_name="$1"

Expand Down
1 change: 1 addition & 0 deletions core/api/src/app/users/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { UsersRepository } from "@/services/mongoose"
export * from "./update-language"
export * from "./get-user-language"
export * from "./add-device-token"
export * from "./list-sessions"

const users = UsersRepository()

Expand Down
11 changes: 11 additions & 0 deletions core/api/src/app/users/list-sessions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { listSessions as listSessionsService } from "@/services/kratos"

export const listMobileSessions = async (userId: UserId) => {
const list = await listSessionsService(userId)
console.dir(list)
return list
}

export const listDeleguateSessions = async (userId: UserId) => {

}
10 changes: 9 additions & 1 deletion core/api/src/domain/authentication/index.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,18 @@ type AnyIdentity =
| IdentityPhoneEmail
| IdentityDeviceAccount

type Session = {
type MobileSession = {
identity: AnyIdentity
id: SessionId
expiresAt: Date
issuedAt: Date
}

type ConsentSession = {
scope: string[]
handledAt: Date
remember: boolean
app: string
}

type WithSessionResponse = {
Expand Down
9 changes: 9 additions & 0 deletions core/api/src/graphql/public/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -865,6 +865,12 @@ type MerchantPayload {
"""(Positive) amount of minutes"""
scalar Minutes

type MobileSession {
expiresAt: Timestamp!
id: ID!
issuedAt: Timestamp!
}

type MobileVersions {
currentSupported: Int!
minSupported: Int!
Expand Down Expand Up @@ -1598,6 +1604,9 @@ type User {
"""
language: Language!

"""List of mobile sessions"""
mobileSessions: [MobileSession!]!

"""Phone number with international calling code."""
phone: Phone
supportChat: [SupportMessage!]!
Expand Down
14 changes: 14 additions & 0 deletions core/api/src/graphql/public/types/object/mobile-session.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import Timestamp from "@/graphql/shared/types/scalar/timestamp"

import { GT } from "@/graphql/index"

const MobileSession = GT.Object({
name: "MobileSession",
fields: () => ({
id: { type: GT.NonNullID },
issuedAt: { type: GT.NonNull(Timestamp) },
expiresAt: { type: GT.NonNull(Timestamp) },
}),
})

export default MobileSession
9 changes: 9 additions & 0 deletions core/api/src/graphql/public/types/object/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import Language from "@/graphql/shared/types/scalar/language"
import Username from "@/graphql/shared/types/scalar/username"
import Timestamp from "@/graphql/shared/types/scalar/timestamp"
import GraphQLEmail from "@/graphql/shared/types/object/email"
import MobileSession from "./mobile-session"

const GraphQLUser = GT.Object<User, GraphQLPublicContextAuth>({
name: "User",
Expand Down Expand Up @@ -75,6 +76,14 @@ const GraphQLUser = GT.Object<User, GraphQLPublicContextAuth>({
},
},

mobileSessions: {
type: GT.NonNullList(MobileSession),
description: "List of mobile sessions",
resolve: async (source, args, { user }) => {
return Users.listMobileSessions(user.id)
},
},

contacts: {
deprecationReason: "will be moved to account",
type: GT.NonNullList(AccountContact), // TODO: Make it a Connection Interface
Expand Down
35 changes: 35 additions & 0 deletions core/api/src/services/hydra/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import axios, { AxiosResponse } from "axios"

const hydraUrl = process.env.HYDRA_ADMIN_URL || "http://localhost:4445"

export const consentList = async (userId: UserId): Promise<ConsentSession[]> => {
let res: AxiosResponse<any, any>

try {
res = await axios.get(
`${hydraUrl}/admin/oauth2/auth/sessions/consent?subject=${userId}`,
)
} catch (err) {
// TODO
console.error(err)
return []
}

let sessions: ConsentSession[]

try {
console.dir(res.data, { depth: null })
sessions = res.data.map((request) => ({
scope: request.grant_scope,
handledAt: new Date(request.handled_at),
remember: request.remember,
app: request.consent_request.client.client_name,
}))
} catch (err) {
// TODO
console.error(err)
return []
}

return sessions
}
6 changes: 4 additions & 2 deletions core/api/src/services/kratos/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const checkedToAuthToken = (value: string) => {
export const validateKratosToken = async (
authToken: AuthToken,
): Promise<ValidateKratosTokenResult | KratosError> => {
let session: Session
let session: MobileSession

try {
const { data } = await kratosPublic.toSession({ xSessionToken: authToken })
Expand All @@ -80,7 +80,9 @@ export const validateKratosToken = async (
}
}

export const listSessions = async (userId: UserId): Promise<Session[] | KratosError> => {
export const listSessions = async (
userId: UserId,
): Promise<MobileSession[] | KratosError> => {
try {
const res = await kratosAdmin.listIdentitySessions({ id: userId })
if (res.data === null) return []
Expand Down
2 changes: 1 addition & 1 deletion core/api/src/services/kratos/index.types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ type IdentitySchemaContainer = import("@ory/client").IdentitySchemaContainer

type ValidateKratosTokenResult = {
kratosUserId: UserId
session: Session
session: MobileSession
}

type KratosPublicMetadata = {
Expand Down
Loading

0 comments on commit b342e0a

Please sign in to comment.