mirror of
https://github.com/strapi/strapi.git
synced 2025-10-29 00:49:49 +00:00
Merge pull request #10704 from strapi/migration/sso-providers-view
Migration SSO providers view - To merge after login view
This commit is contained in:
commit
ec1d8e6829
@ -1,3 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const GoogleStrategy = require('passport-google-oauth2');
|
||||
|
||||
module.exports = ({ env }) => ({
|
||||
host: env('HOST', '0.0.0.0'),
|
||||
port: env.int('PORT', 1337),
|
||||
@ -5,6 +9,32 @@ module.exports = ({ env }) => ({
|
||||
// autoOpen: true,
|
||||
auth: {
|
||||
secret: env('ADMIN_JWT_SECRET', 'example-token'),
|
||||
providers: [
|
||||
{
|
||||
uid: 'google',
|
||||
displayName: 'Google',
|
||||
icon: 'https://cdn2.iconfinder.com/data/icons/social-icons-33/128/Google-512.png',
|
||||
createStrategy: strapi =>
|
||||
new GoogleStrategy(
|
||||
{
|
||||
clientID: env('GOOGLE_CLIENT_ID'),
|
||||
clientSecret: env('GOOGLE_CLIENT_SECRET'),
|
||||
scope: [
|
||||
'https://www.googleapis.com/auth/userinfo.email',
|
||||
'https://www.googleapis.com/auth/userinfo.profile',
|
||||
],
|
||||
callbackURL: strapi.admin.services.passport.getStrategyCallbackURL('google'),
|
||||
},
|
||||
(request, accessToken, refreshToken, profile, done) => {
|
||||
done(null, {
|
||||
email: profile.email,
|
||||
firstname: profile.given_name,
|
||||
lastname: profile.family_name,
|
||||
});
|
||||
}
|
||||
),
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
"@strapi/utils": "3.6.6",
|
||||
"lodash": "4.17.21",
|
||||
"mysql": "2.18.1",
|
||||
"passport-google-oauth2": "0.2.0",
|
||||
"pg": "8.6.0",
|
||||
"sqlite3": "5.0.2",
|
||||
"strapi-middleware-views": "3.6.6"
|
||||
|
||||
@ -13,24 +13,34 @@ export const Column = styled(Row)`
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
export const LayoutContent = ({ children }) => (
|
||||
<Wrapper
|
||||
shadow="tableShadow"
|
||||
hasRadius
|
||||
paddingTop="9"
|
||||
paddingBottom="9"
|
||||
paddingLeft="10"
|
||||
paddingRight="10"
|
||||
background="neutral0"
|
||||
justifyContent="center"
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
);
|
||||
LayoutContent.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
const UnauthenticatedLayout = ({ children }) => {
|
||||
return (
|
||||
<div>
|
||||
<Row as="header" justifyContent="flex-end">
|
||||
<Box paddingTop={6} paddingRight={8}>
|
||||
<LocaleToggle isLogged />
|
||||
<LocaleToggle />
|
||||
</Box>
|
||||
</Row>
|
||||
<Box paddingTop="11" paddingBottom="11">
|
||||
<Wrapper
|
||||
shadow="tableShadow"
|
||||
hasRadius
|
||||
padding="10"
|
||||
background="neutral0"
|
||||
justifyContent="center"
|
||||
>
|
||||
{children}
|
||||
</Wrapper>
|
||||
{children}
|
||||
</Box>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -11,13 +11,15 @@ import {
|
||||
TextInput,
|
||||
Main,
|
||||
FieldAction,
|
||||
Row,
|
||||
Link,
|
||||
} from '@strapi/parts';
|
||||
import PropTypes from 'prop-types';
|
||||
import styled from 'styled-components';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { Formik } from 'formik';
|
||||
|
||||
import { Column } from '../../../../layouts/UnauthenticatedLayout';
|
||||
import { Column, LayoutContent } from '../../../../layouts/UnauthenticatedLayout';
|
||||
import Form from './Form';
|
||||
import Logo from '../Logo';
|
||||
|
||||
@ -35,101 +37,113 @@ const FieldActionWrapper = styled(FieldAction)`
|
||||
}
|
||||
`;
|
||||
|
||||
const Login = ({ onSubmit, schema }) => {
|
||||
const Login = ({ onSubmit, schema, children }) => {
|
||||
const [passwordShown, setPasswordShown] = useState(false);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
return (
|
||||
<Main labelledBy="welcome">
|
||||
<Formik
|
||||
enableReinitialize
|
||||
initialValues={{
|
||||
email: '',
|
||||
password: '',
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
validationSchema={schema}
|
||||
validateOnChange={false}
|
||||
>
|
||||
{({ values, errors, handleChange }) => (
|
||||
<Form noValidate>
|
||||
<Column>
|
||||
<Logo />
|
||||
<Box paddingTop="6" paddingBottom="1">
|
||||
<H1 id="welcome">{formatMessage({ id: 'Auth.form.welcome.title' })}</H1>
|
||||
</Box>
|
||||
<Box paddingBottom="7">
|
||||
<Subtitle textColor="neutral600">
|
||||
{formatMessage({ id: 'Auth.form.welcome.subtitle' })}
|
||||
</Subtitle>
|
||||
</Box>
|
||||
{errors.errorMessage && (
|
||||
<Text id="global-form-error" role="alert" tabIndex={-1} textColor="danger600">
|
||||
{errors.errorMessage}
|
||||
</Text>
|
||||
)}
|
||||
</Column>
|
||||
<LayoutContent>
|
||||
<Formik
|
||||
enableReinitialize
|
||||
initialValues={{
|
||||
email: '',
|
||||
password: '',
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
validationSchema={schema}
|
||||
validateOnChange={false}
|
||||
>
|
||||
{({ values, errors, handleChange }) => (
|
||||
<Form noValidate>
|
||||
<Column>
|
||||
<Logo />
|
||||
<Box paddingTop="6" paddingBottom="1">
|
||||
<H1 id="welcome">{formatMessage({ id: 'Auth.form.welcome.title' })}</H1>
|
||||
</Box>
|
||||
<Box paddingBottom="7">
|
||||
<Subtitle textColor="neutral600">
|
||||
{formatMessage({ id: 'Auth.form.welcome.subtitle' })}
|
||||
</Subtitle>
|
||||
</Box>
|
||||
{errors.errorMessage && (
|
||||
<Text id="global-form-error" role="alert" tabIndex={-1} textColor="danger600">
|
||||
{errors.errorMessage}
|
||||
</Text>
|
||||
)}
|
||||
</Column>
|
||||
|
||||
<Stack size={6}>
|
||||
<TextInput
|
||||
error={errors.email ? formatMessage({ id: errors.email }) : ''}
|
||||
value={values.email}
|
||||
onChange={handleChange}
|
||||
label={formatMessage({ id: 'Auth.form.email.label' })}
|
||||
placeholder={formatMessage({ id: 'Auth.form.email.placeholder' })}
|
||||
name="email"
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
error={errors.password ? formatMessage({ id: errors.password }) : ''}
|
||||
onChange={handleChange}
|
||||
value={values.password}
|
||||
label={formatMessage({ id: 'Auth.form.password.label' })}
|
||||
name="password"
|
||||
type={passwordShown ? 'text' : 'password'}
|
||||
endAction={
|
||||
// eslint-disable-next-line react/jsx-wrap-multilines
|
||||
<FieldActionWrapper
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setPasswordShown(prev => !prev);
|
||||
}}
|
||||
label={formatMessage({
|
||||
id: passwordShown
|
||||
? 'Auth.form.password.show-password'
|
||||
: 'Auth.form.password.hide-password',
|
||||
})}
|
||||
>
|
||||
{passwordShown ? <Show /> : <Hide />}
|
||||
</FieldActionWrapper>
|
||||
}
|
||||
required
|
||||
/>
|
||||
<Checkbox
|
||||
onValueChange={checked => {
|
||||
handleChange({ target: { value: checked, name: 'rememberMe' } });
|
||||
}}
|
||||
value={values.rememberMe}
|
||||
name="rememberMe"
|
||||
>
|
||||
{formatMessage({ id: 'Auth.form.rememberMe.label' })}
|
||||
</Checkbox>
|
||||
<AuthButton type="submit">
|
||||
{formatMessage({ id: 'Auth.form.button.login' })}
|
||||
</AuthButton>
|
||||
</Stack>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
<Stack size={6}>
|
||||
<TextInput
|
||||
error={errors.email ? formatMessage({ id: errors.email }) : ''}
|
||||
value={values.email}
|
||||
onChange={handleChange}
|
||||
label={formatMessage({ id: 'Auth.form.email.label' })}
|
||||
placeholder={formatMessage({ id: 'Auth.form.email.placeholder' })}
|
||||
name="email"
|
||||
required
|
||||
/>
|
||||
<TextInput
|
||||
error={errors.password ? formatMessage({ id: errors.password }) : ''}
|
||||
onChange={handleChange}
|
||||
value={values.password}
|
||||
label={formatMessage({ id: 'Auth.form.password.label' })}
|
||||
name="password"
|
||||
type={passwordShown ? 'text' : 'password'}
|
||||
endAction={
|
||||
// eslint-disable-next-line react/jsx-wrap-multilines
|
||||
<FieldActionWrapper
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
setPasswordShown(prev => !prev);
|
||||
}}
|
||||
label={formatMessage({
|
||||
id: passwordShown
|
||||
? 'Auth.form.password.show-password'
|
||||
: 'Auth.form.password.hide-password',
|
||||
})}
|
||||
>
|
||||
{passwordShown ? <Show /> : <Hide />}
|
||||
</FieldActionWrapper>
|
||||
}
|
||||
required
|
||||
/>
|
||||
<Checkbox
|
||||
onValueChange={checked => {
|
||||
handleChange({ target: { value: checked, name: 'rememberMe' } });
|
||||
}}
|
||||
value={values.rememberMe}
|
||||
name="rememberMe"
|
||||
>
|
||||
{formatMessage({ id: 'Auth.form.rememberMe.label' })}
|
||||
</Checkbox>
|
||||
<AuthButton type="submit">
|
||||
{formatMessage({ id: 'Auth.form.button.login' })}
|
||||
</AuthButton>
|
||||
</Stack>
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
{children}
|
||||
</LayoutContent>
|
||||
<Row justifyContent="center">
|
||||
<Box paddingTop={4}>
|
||||
<Link to="/auth/forgot-password">
|
||||
<Text small>{formatMessage({ id: 'Auth.link.forgot-password' })}</Text>
|
||||
</Link>
|
||||
</Box>
|
||||
</Row>
|
||||
</Main>
|
||||
);
|
||||
};
|
||||
|
||||
Login.defaultProps = {
|
||||
children: null,
|
||||
onSubmit: () => {},
|
||||
};
|
||||
|
||||
Login.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onSubmit: PropTypes.func,
|
||||
schema: PropTypes.shape({
|
||||
type: PropTypes.string.isRequired,
|
||||
|
||||
@ -6,13 +6,7 @@ const FormWithFocus = props => {
|
||||
|
||||
useEffect(() => {
|
||||
if (isSubmitting && !isValidating) {
|
||||
const errorNames = Object.keys(touched).reduce((prev, key) => {
|
||||
if (getIn(errors, key)) {
|
||||
prev.push(key);
|
||||
}
|
||||
|
||||
return prev;
|
||||
}, []);
|
||||
const errorNames = Object.keys(touched).filter(error => getIn(errors, error));
|
||||
|
||||
if (errorNames.length) {
|
||||
let errorEl;
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
"Auth.form.button.login": "Login",
|
||||
"Auth.form.button.login.providers.error": "We cannot connect you through the selected provider.",
|
||||
"Auth.form.button.login.providers.see-more": "See more",
|
||||
"Auth.form.button.login.strapi": "LOG IN VIA STRAPI",
|
||||
"Auth.form.button.login.strapi": "Log in via Strapi",
|
||||
"Auth.form.button.register": "LET'S START",
|
||||
"Auth.form.button.reset-password": "Change password",
|
||||
"Auth.form.confirmPassword.label": "Confirmation Password",
|
||||
@ -47,6 +47,8 @@
|
||||
"Auth.link.signin": "Sign in",
|
||||
"Auth.link.signin.account": "Already have an account?",
|
||||
"Auth.login.sso.divider": "Or login with",
|
||||
"Auth.login.sso.loading": "Loading providers...",
|
||||
"Auth.login.sso.subtitle": "Login to your account via SSO",
|
||||
"Auth.privacy-policy-agreement.policy": "privacy policy",
|
||||
"Auth.privacy-policy-agreement.terms": "terms",
|
||||
"Content Manager": "Content Manager",
|
||||
|
||||
@ -27,21 +27,22 @@ const Login = loginProps => {
|
||||
|
||||
return (
|
||||
<UnauthenticatedLayout>
|
||||
<BaseLogin {...loginProps} />
|
||||
<Box paddingTop={7}>
|
||||
<Stack size={7}>
|
||||
<Row>
|
||||
<DividerFull />
|
||||
<Box paddingLeft={3} paddingRight={3}>
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({ id: 'Auth.login.sso.divider' })}
|
||||
</TableLabel>
|
||||
</Box>
|
||||
<DividerFull />
|
||||
</Row>
|
||||
<SSOProviders providers={providers} displayAllProviders={false} />
|
||||
</Stack>
|
||||
</Box>
|
||||
<BaseLogin {...loginProps}>
|
||||
<Box paddingTop={7}>
|
||||
<Stack size={7}>
|
||||
<Row>
|
||||
<DividerFull />
|
||||
<Box paddingLeft={3} paddingRight={3}>
|
||||
<TableLabel textColor="neutral600">
|
||||
{formatMessage({ id: 'Auth.login.sso.divider' })}
|
||||
</TableLabel>
|
||||
</Box>
|
||||
<DividerFull />
|
||||
</Row>
|
||||
<SSOProviders providers={providers} displayAllProviders={false} />
|
||||
</Stack>
|
||||
</Box>
|
||||
</BaseLogin>
|
||||
</UnauthenticatedLayout>
|
||||
);
|
||||
};
|
||||
|
||||
@ -84,7 +84,7 @@ const SSOProviders = ({ providers, displayAllProviders }) => {
|
||||
})}
|
||||
>
|
||||
<SSOButton as={Link} to="/auth/providers">
|
||||
<span aroa-hidden>•••</span>
|
||||
<span aria-hidden>•••</span>
|
||||
</SSOButton>
|
||||
</Tooltip>
|
||||
</GridItem>
|
||||
|
||||
@ -1,18 +1,35 @@
|
||||
import React from 'react';
|
||||
import { Button, Flex, Padded, Separator } from '@buffetjs/core';
|
||||
import { LoadingIndicator } from '@buffetjs/styles';
|
||||
import { Redirect, useHistory } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
import {
|
||||
Divider,
|
||||
Stack,
|
||||
Row,
|
||||
Box,
|
||||
TableLabel,
|
||||
Button,
|
||||
Main,
|
||||
Subtitle,
|
||||
H1,
|
||||
Link,
|
||||
Text,
|
||||
Loader,
|
||||
} from '@strapi/parts';
|
||||
import { useIntl } from 'react-intl';
|
||||
import { BaselineAlignment } from '@strapi/helper-plugin';
|
||||
import Box from '../../../../../../admin/src/pages/AuthPage/components/Box';
|
||||
import Logo from '../../../../../../admin/src/pages/AuthPage/components/Logo';
|
||||
import Section from '../../../../../../admin/src/pages/AuthPage/components/Section';
|
||||
import ProviderButton from '../../../../components/ProviderButton';
|
||||
import { useAuthProviders } from '../../../../hooks';
|
||||
import UnauthenticatedLayout, {
|
||||
Column,
|
||||
LayoutContent,
|
||||
} from '../../../../../../admin/src/layouts/UnauthenticatedLayout';
|
||||
import SSOProviders from './SSOProviders';
|
||||
import Logo from '../../../../../../admin/src/pages/AuthPage/components/Logo';
|
||||
|
||||
const ProviderWrapper = styled.div`
|
||||
padding: 5px 4px;
|
||||
const DividerFull = styled(Divider)`
|
||||
flex: 1;
|
||||
`;
|
||||
const AuthButton = styled(Button)`
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
`;
|
||||
|
||||
const Providers = () => {
|
||||
@ -31,44 +48,49 @@ const Providers = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Section textAlign="center">
|
||||
<Logo />
|
||||
</Section>
|
||||
<Section withBackground textAlign="center">
|
||||
<BaselineAlignment top size="25px">
|
||||
<Box withoutError>
|
||||
<UnauthenticatedLayout>
|
||||
<Main labelledBy="welcome">
|
||||
<LayoutContent>
|
||||
<Column>
|
||||
<Logo />
|
||||
<Box paddingTop="6" paddingBottom="1">
|
||||
<H1 id="welcome">{formatMessage({ id: 'Auth.form.welcome.title' })}</H1>
|
||||
</Box>
|
||||
<Box paddingBottom="7">
|
||||
<Subtitle textColor="neutral600">
|
||||
{formatMessage({ id: 'Auth.login.sso.subtitle' })}
|
||||
</Subtitle>
|
||||
</Box>
|
||||
</Column>
|
||||
<Stack size={7}>
|
||||
{isLoading ? (
|
||||
<LoadingIndicator />
|
||||
<Row justifyContent="center">
|
||||
<Loader>{formatMessage({ id: 'Auth.login.sso.loading' })}</Loader>
|
||||
</Row>
|
||||
) : (
|
||||
<Flex flexWrap="wrap">
|
||||
{providers.map(provider => (
|
||||
<ProviderWrapper key={provider.uid}>
|
||||
<ProviderButton provider={provider} />
|
||||
</ProviderWrapper>
|
||||
))}
|
||||
</Flex>
|
||||
<SSOProviders providers={providers} />
|
||||
)}
|
||||
<Padded top bottom size="smd">
|
||||
<BaselineAlignment top size="3px" />
|
||||
<Separator
|
||||
label={formatMessage({
|
||||
id: 'or',
|
||||
defaultMessage: 'OR',
|
||||
})}
|
||||
/>
|
||||
<BaselineAlignment top size="7px" />
|
||||
</Padded>
|
||||
<Button style={{ width: '100%' }} onClick={handleClick} type="submit" color="secondary">
|
||||
{formatMessage({
|
||||
id: 'Auth.form.button.login.strapi',
|
||||
defaultMessage: 'LOG IN VIA STRAPI',
|
||||
})}
|
||||
</Button>
|
||||
<Row>
|
||||
<DividerFull />
|
||||
<Box paddingLeft={3} paddingRight={3}>
|
||||
<TableLabel textColor="neutral600">{formatMessage({ id: 'or' })}</TableLabel>
|
||||
</Box>
|
||||
<DividerFull />
|
||||
</Row>
|
||||
<AuthButton onClick={handleClick}>
|
||||
{formatMessage({ id: 'Auth.form.button.login.strapi' })}
|
||||
</AuthButton>
|
||||
</Stack>
|
||||
</LayoutContent>
|
||||
<Row justifyContent="center">
|
||||
<Box paddingTop={4}>
|
||||
<Link to="/auth/forgot-password">
|
||||
<Text small>{formatMessage({ id: 'Auth.link.forgot-password' })}</Text>
|
||||
</Link>
|
||||
</Box>
|
||||
</BaselineAlignment>
|
||||
</Section>
|
||||
</>
|
||||
</Row>
|
||||
</Main>
|
||||
</UnauthenticatedLayout>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
35
yarn.lock
35
yarn.lock
@ -5558,6 +5558,11 @@ base64-js@^1.0.2, base64-js@^1.3.0, base64-js@^1.3.1:
|
||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a"
|
||||
integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==
|
||||
|
||||
base64url@3.x.x:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/base64url/-/base64url-3.0.1.tgz#6399d572e2bc3f90a9a8b22d5dbb0a32d33f788d"
|
||||
integrity sha512-ir1UPr3dkwexU7FdV8qBBbNDRUhMmIekYMFZfi+C/sLNnRESKPl23nB9b2pltqfOQNnGzsDdId90AEtG5tCx4A==
|
||||
|
||||
base@^0.11.1:
|
||||
version "0.11.2"
|
||||
resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
|
||||
@ -15115,6 +15120,11 @@ oauth-sign@^0.9.0, oauth-sign@~0.9.0:
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
oauth@0.9.x:
|
||||
version "0.9.15"
|
||||
resolved "https://registry.yarnpkg.com/oauth/-/oauth-0.9.15.tgz#bd1fefaf686c96b75475aed5196412ff60cfb9c1"
|
||||
integrity sha1-vR/vr2hslrdUda7VGWQS/2DPucE=
|
||||
|
||||
object-assign@4.x, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
|
||||
version "4.1.1"
|
||||
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
|
||||
@ -15813,6 +15823,13 @@ pascalcase@^0.1.1:
|
||||
resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
|
||||
integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
|
||||
|
||||
passport-google-oauth2@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-google-oauth2/-/passport-google-oauth2-0.2.0.tgz#fc9ea59e7091f02e24fd16d6be9257ea982ebbc3"
|
||||
integrity sha512-62EdPtbfVdc55nIXi0p1WOa/fFMM8v/M8uQGnbcXA4OexZWCnfsEi3wo2buag+Is5oqpuHzOtI64JpHk0Xi5RQ==
|
||||
dependencies:
|
||||
passport-oauth2 "^1.1.2"
|
||||
|
||||
passport-local@1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-local/-/passport-local-1.0.0.tgz#1fe63268c92e75606626437e3b906662c15ba6ee"
|
||||
@ -15820,6 +15837,17 @@ passport-local@1.0.0:
|
||||
dependencies:
|
||||
passport-strategy "1.x.x"
|
||||
|
||||
passport-oauth2@^1.1.2:
|
||||
version "1.6.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-oauth2/-/passport-oauth2-1.6.0.tgz#5f599735e0ea40ea3027643785f81a3a9b4feb50"
|
||||
integrity sha512-emXPLqLcVEcLFR/QvQXZcwLmfK8e9CqvMgmOFJxcNT3okSFMtUbRRKpY20x5euD+01uHsjjCa07DYboEeLXYiw==
|
||||
dependencies:
|
||||
base64url "3.x.x"
|
||||
oauth "0.9.x"
|
||||
passport-strategy "1.x.x"
|
||||
uid2 "0.0.x"
|
||||
utils-merge "1.x.x"
|
||||
|
||||
passport-strategy@1.x.x:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/passport-strategy/-/passport-strategy-1.0.0.tgz#b5539aa8fc225a3d1ad179476ddf236b440f52e4"
|
||||
@ -20800,6 +20828,11 @@ uid-number@0.0.6:
|
||||
resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81"
|
||||
integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE=
|
||||
|
||||
uid2@0.0.x:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/uid2/-/uid2-0.0.3.tgz#483126e11774df2f71b8b639dcd799c376162b82"
|
||||
integrity sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=
|
||||
|
||||
umask@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d"
|
||||
@ -21139,7 +21172,7 @@ utila@~0.4:
|
||||
resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
|
||||
integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
|
||||
|
||||
utils-merge@1.0.1:
|
||||
utils-merge@1.0.1, utils-merge@1.x.x:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user