[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:
Kiwi
2018-12-20 22:32:04 +01:00
committed by GitHub
parent 326a10dc5d
commit 065cb4b03a
331 changed files with 12476 additions and 7163 deletions
+9 -166
View File
@@ -5,10 +5,7 @@ import uuid from "uuid";
import { DeepPartial, Omit, Sub } from "talk-common/types";
import { dotize, DotizeOptions } from "talk-common/utils/dotize";
import {
GQLMODERATION_MODE,
GQLOIDCAuthIntegration,
} from "talk-server/graph/tenant/schema/__generated__/types";
import { GQLMODERATION_MODE } from "talk-server/graph/tenant/schema/__generated__/types";
import { Settings } from "talk-server/models/settings";
function collection(db: Db) {
@@ -114,11 +111,17 @@ export async function createTenant(mongo: Db, input: CreateTenantInput) {
key: generateSSOKey(),
keyGeneratedAt: new Date(),
},
oidc: [],
oidc: {
enabled: false,
allowRegistration: false,
targetFilter: {
admin: true,
stream: true,
},
},
google: {
enabled: false,
allowRegistration: false,
callbackURL: "" as any, // FIXME: this should not be required
targetFilter: {
admin: true,
stream: true,
@@ -127,7 +130,6 @@ export async function createTenant(mongo: Db, input: CreateTenantInput) {
facebook: {
enabled: false,
allowRegistration: false,
callbackURL: "", // FIXME: this should not be required
targetFilter: {
admin: true,
stream: true,
@@ -282,162 +284,3 @@ export async function regenerateTenantSSOKey(db: Db, id: string) {
return result.value || null;
}
export type CreateTenantOIDCAuthIntegrationInput = Omit<
GQLOIDCAuthIntegration,
"id" | "callbackURL"
>;
export interface CreateTenantOIDCAuthIntegrationResultObject {
tenant?: Tenant;
integration?: Omit<GQLOIDCAuthIntegration, "callbackURL">;
wasCreated: boolean;
}
export async function createTenantOIDCAuthIntegration(
mongo: Db,
id: string,
input: CreateTenantOIDCAuthIntegrationInput
): Promise<CreateTenantOIDCAuthIntegrationResultObject> {
// Add the ID to the integration.
const integration = {
id: uuid.v4(),
...input,
};
const result = await collection(mongo).findOneAndUpdate(
{ id },
// Serialize the deep update into the Tenant.
{
$push: { "auth.integrations.oidc": integration },
},
// False to return the updated document instead of the original
// document.
{ returnOriginal: false }
);
if (!result.value) {
return {
wasCreated: false,
};
}
const wasCreated =
result.value.auth.integrations.oidc.findIndex(
({ id: integrationID }) => integrationID === integration.id
) !== -1;
return {
tenant: result.value,
integration,
wasCreated,
};
}
export type UpdateTenantOIDCAuthIntegrationInput = Partial<
Omit<GQLOIDCAuthIntegration, "id">
>;
export interface UpdateTenantOIDCAuthIntegrationResultObject {
tenant?: Tenant;
integration?: Omit<GQLOIDCAuthIntegration, "callbackURL">;
wasUpdated: boolean;
}
export async function updateTenantOIDCAuthIntegration(
mongo: Db,
id: string,
oidcID: string,
input: UpdateTenantOIDCAuthIntegrationInput
): Promise<UpdateTenantOIDCAuthIntegrationResultObject> {
const result = await collection(mongo).findOneAndUpdate(
{ id },
{
$set: dotizeDropNull({
"auth.integrations.oidc.$[oidc]": input,
}),
},
{
// Add an ArrayFilter to only update one of the OpenID Connect
// integrations.
arrayFilters: [{ "oidc.id": oidcID }],
// False to return the updated document instead of the original
// document.
returnOriginal: false,
}
);
if (!result.value) {
return {
wasUpdated: false,
};
}
const integration = result.value.auth.integrations.oidc.find(
({ id: integrationID }) => integrationID === oidcID
);
const wasUpdated = Boolean(integration);
return {
tenant: result.value,
integration,
wasUpdated,
};
}
export interface RemoveTenantOIDCAuthIntegrationResultObject {
tenant?: Tenant;
integration?: Omit<GQLOIDCAuthIntegration, "callbackURL">;
wasRemoved: boolean;
}
/**
* removeTenantOIDCAuthIntegration will delete the specific OpenID Connect Auth
* Integration on the Tenant.
*
* @param mongo MongoDB Database handle
* @param id the id of the Tenant
* @param oidcID the id of the OpenID Connect Auth Integration we're deleting
*/
export async function removeTenantOIDCAuthIntegration(
mongo: Db,
id: string,
oidcID: string
): Promise<RemoveTenantOIDCAuthIntegrationResultObject> {
const result = await collection(mongo).findOneAndUpdate(
{ id },
{
$pull: { "auth.integrations.oidc": { id: oidcID } },
},
{
// True to return the document before we modified it. This gives us the
// opportunity to return the original document and asertain if the
// integration was/could be removed.
returnOriginal: true,
}
);
if (!result.value) {
return { wasRemoved: false };
}
// Find the integration that we wanted to delete.
const integration = result.value.auth.integrations.oidc.find(
({ id: integrationID }) => integrationID === oidcID
);
if (!integration) {
// The integration was not in the original document, so we could not have
// possibly deleted it!
return { wasRemoved: false };
}
// The integration was found, we should pull that integration out of the
// resulting Tenant.
result.value.auth.integrations.oidc.filter(
({ id: integrationID }) => integrationID !== integration.id
);
return {
tenant: result.value,
integration,
wasRemoved: true,
};
}