mirror of
https://github.com/wassname/talk.git
synced 2026-07-20 12:40:47 +08:00
[next] Auth Popup v2 (#2101)
* feat: Implement new Sign In view * feat: Move forgot + resetPassword to new design * feat: Implement sign up with new design * fix: narrow gutter * test: add unit tests * test: integration tests * feat: support show / hide password * feat: support oauth2 flow * feat: add views for user completion * feat: implement oauth2 sign up * test: fix snapshots * fix: lint * fix: get more complete mutation response * fix: removed array of OIDC integrations * fix: renamed resolver function * fix: adapt oidc client implementation * fix: targetFilter should be stream on signup * fix: removed unneeded message * fix: moved password into local profile * fix: made username optional, removed valid null value * fix: linting * fix: respect targetFilter * feat: support user registration mutations - Added `setUsername` - Added `setEmail` - Added `setPassword` - Added `permit` to `@auth` - Added `email` to `User` * fix: fixed issue with query * feat: added user password update * feat: complete sign in mutation * fix: adapt some rebasing gitches * test: improve tests * test: unittest for setting auth token * fix: failing tests * test: move most tests from enzyme to react-test-renderer * fix: remove schema warnings in tests * test: improve window mock * test: test different social login configurations * test: test social logins for sign up * fix: use htmlFor instead of for * test: more feature tests * feat: always go through account completion * test: feature test account completion * feat: addtional account completion test * Update start.ts * chore: refactor auth token retrieval logic
This commit is contained in:
@@ -2,20 +2,13 @@ import { Redis } from "ioredis";
|
||||
import { Db } from "mongodb";
|
||||
import { URL } from "url";
|
||||
|
||||
import {
|
||||
GQLCreateOIDCAuthIntegrationConfigurationInput,
|
||||
GQLSettingsInput,
|
||||
GQLUpdateOIDCAuthIntegrationConfigurationInput,
|
||||
} from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import { GQLSettingsInput } from "talk-server/graph/tenant/schema/__generated__/types";
|
||||
import {
|
||||
createTenant,
|
||||
CreateTenantInput,
|
||||
createTenantOIDCAuthIntegration,
|
||||
regenerateTenantSSOKey,
|
||||
removeTenantOIDCAuthIntegration,
|
||||
Tenant,
|
||||
updateTenant,
|
||||
updateTenantOIDCAuthIntegration,
|
||||
} from "talk-server/models/tenant";
|
||||
|
||||
import { discover } from "talk-server/app/middleware/passport/strategies/oidc/discover";
|
||||
@@ -123,82 +116,3 @@ export async function discoverOIDCConfiguration(issuerString: string) {
|
||||
// Discover the configuration.
|
||||
return discover(issuer);
|
||||
}
|
||||
|
||||
export type CreateOIDCAuthIntegration = GQLCreateOIDCAuthIntegrationConfigurationInput;
|
||||
|
||||
export async function createOIDCAuthIntegration(
|
||||
mongo: Db,
|
||||
redis: Redis,
|
||||
cache: TenantCache,
|
||||
tenant: Tenant,
|
||||
input: CreateOIDCAuthIntegration
|
||||
) {
|
||||
// Create the integration. By default, the integration is disabled.
|
||||
const result = await createTenantOIDCAuthIntegration(mongo, tenant.id, {
|
||||
enabled: false,
|
||||
allowRegistration: false,
|
||||
targetFilter: {
|
||||
admin: true,
|
||||
stream: true,
|
||||
},
|
||||
...input,
|
||||
});
|
||||
if (!result.wasCreated || !result.tenant) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update the tenant cache.
|
||||
await cache.update(redis, result.tenant);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export type UpdateOIDCAuthIntegration = GQLUpdateOIDCAuthIntegrationConfigurationInput;
|
||||
|
||||
export async function updateOIDCAuthIntegration(
|
||||
mongo: Db,
|
||||
redis: Redis,
|
||||
cache: TenantCache,
|
||||
tenant: Tenant,
|
||||
oidcID: string,
|
||||
input: UpdateOIDCAuthIntegration
|
||||
) {
|
||||
// Update the integration. By default, the integration is disabled.
|
||||
const result = await updateTenantOIDCAuthIntegration(
|
||||
mongo,
|
||||
tenant.id,
|
||||
oidcID,
|
||||
input
|
||||
);
|
||||
if (!result.wasUpdated || !result.tenant) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update the tenant cache.
|
||||
await cache.update(redis, result.tenant);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
export async function removeOIDCAuthIntegration(
|
||||
mongo: Db,
|
||||
redis: Redis,
|
||||
cache: TenantCache,
|
||||
tenant: Tenant,
|
||||
oidcID: string
|
||||
) {
|
||||
// Delete the integration. By default, the integration is disabled.
|
||||
const result = await removeTenantOIDCAuthIntegration(
|
||||
mongo,
|
||||
tenant.id,
|
||||
oidcID
|
||||
);
|
||||
if (!result.wasRemoved || !result.tenant) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update the tenant cache.
|
||||
await cache.update(redis, result.tenant);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,15 @@
|
||||
import { Db } from "mongodb";
|
||||
|
||||
import { Tenant } from "talk-server/models/tenant";
|
||||
import { upsertUser, UpsertUserInput } from "talk-server/models/user";
|
||||
import {
|
||||
setUserEmail,
|
||||
setUserLocalProfile,
|
||||
setUserUsername,
|
||||
updateUserPassword,
|
||||
upsertUser,
|
||||
UpsertUserInput,
|
||||
User,
|
||||
} from "talk-server/models/user";
|
||||
|
||||
export type UpsertUser = UpsertUserInput;
|
||||
|
||||
@@ -10,3 +18,74 @@ export async function upsert(db: Db, tenant: Tenant, input: UpsertUser) {
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
export async function setUsername(
|
||||
mongo: Db,
|
||||
tenant: Tenant,
|
||||
user: User,
|
||||
username: string
|
||||
) {
|
||||
// We require that the username is not defined in order to use this method.
|
||||
if (user.username) {
|
||||
throw new Error("username already associated with user");
|
||||
}
|
||||
|
||||
return setUserUsername(mongo, tenant.id, user.id, username);
|
||||
}
|
||||
|
||||
export async function setEmail(
|
||||
mongo: Db,
|
||||
tenant: Tenant,
|
||||
user: User,
|
||||
email: string
|
||||
) {
|
||||
// We requires that the email address is not defined in order to use this
|
||||
// method.
|
||||
if (user.email) {
|
||||
throw new Error("email address already associated with user");
|
||||
}
|
||||
|
||||
return setUserEmail(mongo, tenant.id, user.id, email);
|
||||
}
|
||||
|
||||
export async function setPassword(
|
||||
mongo: Db,
|
||||
tenant: Tenant,
|
||||
user: User,
|
||||
password: string
|
||||
) {
|
||||
// We require that the email address for the user be defined for this method.
|
||||
if (!user.email) {
|
||||
throw new Error("no email address associated with user");
|
||||
}
|
||||
|
||||
// We also don't allow this method to be used by users that already have a
|
||||
// local profile.
|
||||
if (user.profiles.some(({ type }) => type === "local")) {
|
||||
throw new Error("user already has local profile");
|
||||
}
|
||||
|
||||
return setUserLocalProfile(mongo, tenant.id, user.id, user.email, password);
|
||||
}
|
||||
|
||||
export async function updatePassword(
|
||||
mongo: Db,
|
||||
tenant: Tenant,
|
||||
user: User,
|
||||
password: string
|
||||
) {
|
||||
// We require that the email address for the user be defined for this method.
|
||||
if (!user.email) {
|
||||
throw new Error("no email address associated with user");
|
||||
}
|
||||
|
||||
// We also don't allow this method to be used by users that don't have a local
|
||||
// profile already.
|
||||
if (
|
||||
!user.profiles.some(({ id, type }) => type === "local" && id === user.email)
|
||||
) {
|
||||
throw new Error("user does not have a local profile");
|
||||
}
|
||||
|
||||
return updateUserPassword(mongo, tenant.id, user.id, password);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user