Merge pull request #592 from ONLYOFFICE/bugfix/oauth2-scope
Bugfix/oauth2 scope
This commit is contained in:
commit
a77fd92d09
@ -242,7 +242,6 @@ const StyledProperties = styled.div`
|
||||
gap: 4px;
|
||||
|
||||
.property-tag {
|
||||
background: red;
|
||||
max-width: 195px;
|
||||
margin: 0;
|
||||
background: ${(props) => props.theme.infoPanel.details.tagBackground};
|
||||
|
@ -56,6 +56,8 @@ const ScopesBlock = ({
|
||||
) => {
|
||||
const isChecked = checkedScopes.includes(name);
|
||||
|
||||
const isWrite = type === "write";
|
||||
|
||||
if (!isChecked) {
|
||||
setFilteredScopes((val) => {
|
||||
val[group].isChecked = true;
|
||||
@ -88,6 +90,8 @@ const ScopesBlock = ({
|
||||
setCheckedScopes((val) => val.filter((v) => v !== name));
|
||||
}
|
||||
|
||||
if (isWrite) onAddScope("scopes", name.replace("write", "read"));
|
||||
|
||||
onAddScope("scopes", name);
|
||||
};
|
||||
|
||||
|
@ -25,6 +25,7 @@ import { TTranslation } from "@docspace/shared/types";
|
||||
import { ContextMenuModel } from "@docspace/shared/components/context-menu";
|
||||
|
||||
import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore";
|
||||
import { Tag } from "@docspace/shared/components/tag";
|
||||
|
||||
const StyledContainer = styled.div<{
|
||||
showDescription: boolean;
|
||||
@ -118,6 +119,23 @@ const StyledContainer = styled.div<{
|
||||
background: ${(props) => props.theme.oauth.infoDialog.separatorColor};
|
||||
}
|
||||
}
|
||||
|
||||
.property-tag_list {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 4px;
|
||||
|
||||
.property-tag {
|
||||
max-width: 195px;
|
||||
margin: 0;
|
||||
background: ${(props) => props.theme.infoPanel.details.tagBackground};
|
||||
p {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
StyledContainer.defaultProps = { theme: Base };
|
||||
@ -288,7 +306,6 @@ const InfoDialog = ({
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
<Text
|
||||
className="block-header"
|
||||
fontSize="14px"
|
||||
@ -299,7 +316,6 @@ const InfoDialog = ({
|
||||
>
|
||||
{t("Common:Website")}
|
||||
</Text>
|
||||
|
||||
<Link
|
||||
fontSize="13px"
|
||||
lineHeight="15px"
|
||||
@ -311,7 +327,21 @@ const InfoDialog = ({
|
||||
>
|
||||
{client?.websiteUrl}
|
||||
</Link>
|
||||
|
||||
<Text
|
||||
className="block-header"
|
||||
fontSize="14px"
|
||||
lineHeight="16px"
|
||||
fontWeight="600"
|
||||
noSelect
|
||||
truncate
|
||||
>
|
||||
{t("Scopes")}
|
||||
</Text>{" "}
|
||||
<ScopeList
|
||||
selectedScopes={client?.scopes || []}
|
||||
scopes={scopeList || []}
|
||||
t={t}
|
||||
/>
|
||||
<Text
|
||||
className="block-header"
|
||||
fontSize="14px"
|
||||
@ -322,11 +352,16 @@ const InfoDialog = ({
|
||||
>
|
||||
{t("Access")}
|
||||
</Text>
|
||||
<ScopeList
|
||||
selectedScopes={client?.scopes || []}
|
||||
scopes={scopeList || []}
|
||||
t={t}
|
||||
/>
|
||||
<div className="property-tag_list">
|
||||
{client?.scopes.map((scope) => (
|
||||
<Tag
|
||||
key={scope}
|
||||
tag={scope}
|
||||
className="property-tag"
|
||||
label={scope}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{isProfile && (
|
||||
<>
|
||||
<Text
|
||||
@ -351,7 +386,6 @@ const InfoDialog = ({
|
||||
</Text>
|
||||
</>
|
||||
)}
|
||||
|
||||
<Text
|
||||
className="block-header"
|
||||
fontSize="14px"
|
||||
@ -362,7 +396,6 @@ const InfoDialog = ({
|
||||
>
|
||||
{t("SupportAndLegalInfo")}
|
||||
</Text>
|
||||
|
||||
<Text
|
||||
className="privacy-block"
|
||||
fontSize="13px"
|
||||
|
@ -27,6 +27,8 @@ const StyledImage = styled.img`
|
||||
height: 32px;
|
||||
|
||||
border-radius: 3px;
|
||||
|
||||
object-fit: cover;
|
||||
`;
|
||||
|
||||
interface NameCellProps {
|
||||
|
@ -21,9 +21,11 @@ import {
|
||||
import { UserStore } from "@docspace/shared/store/UserStore";
|
||||
|
||||
import { OAuthStoreProps } from "SRC_DIR/store/OAuthStore";
|
||||
import { introspectDeveloperToken } from "@docspace/shared/api/oauth";
|
||||
import { FieldContainer } from "@docspace/shared/components/field-container";
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
p {
|
||||
.warning-text {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
`;
|
||||
@ -42,11 +44,15 @@ const GenerateDeveloperTokenDialog = ({
|
||||
// const {} = useTranslation(["OAuth", "Common"]);
|
||||
|
||||
const [token, setToken] = React.useState("");
|
||||
const [isValidToken, setIsValidToken] = React.useState(false);
|
||||
const [tokenError, setTokenError] = React.useState("");
|
||||
|
||||
const [requestRunning, setRequestRunning] = React.useState(false);
|
||||
|
||||
const timerRef = React.useRef<null | NodeJS.Timeout>(null);
|
||||
|
||||
const onRevoke = async () => {
|
||||
if (!token || !client || requestRunning) return;
|
||||
if (!token || !isValidToken || !client || requestRunning) return;
|
||||
|
||||
try {
|
||||
const { clientId, clientSecret } = client;
|
||||
@ -66,9 +72,42 @@ const GenerateDeveloperTokenDialog = ({
|
||||
}
|
||||
};
|
||||
|
||||
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const onChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const value = e.target.value;
|
||||
|
||||
if (timerRef.current) {
|
||||
clearTimeout(timerRef.current);
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
setIsValidToken(false);
|
||||
setTokenError("");
|
||||
setToken("");
|
||||
return;
|
||||
}
|
||||
|
||||
timerRef.current = setTimeout(async () => {
|
||||
try {
|
||||
const data = await introspectDeveloperToken(value);
|
||||
|
||||
if (!data) return;
|
||||
|
||||
const { active, client_id: clientId } = data;
|
||||
|
||||
if (active && clientId === client?.clientId) {
|
||||
setIsValidToken(true);
|
||||
setTokenError("");
|
||||
return;
|
||||
}
|
||||
|
||||
setIsValidToken(false);
|
||||
setTokenError("Invalid token");
|
||||
} catch (err) {
|
||||
setIsValidToken(false);
|
||||
setTokenError("Invalid token");
|
||||
}
|
||||
}, 200);
|
||||
|
||||
setToken(value);
|
||||
};
|
||||
|
||||
@ -89,16 +128,23 @@ const GenerateDeveloperTokenDialog = ({
|
||||
<ModalDialog.Header>Revoke developer token</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<StyledContainer>
|
||||
<Text>Warning text</Text>
|
||||
<TextInput
|
||||
value={token}
|
||||
scale
|
||||
placeholder="Enter developer token"
|
||||
type={InputType.text}
|
||||
size={InputSize.base}
|
||||
onChange={onChange}
|
||||
maxLength={10000}
|
||||
/>
|
||||
<Text className="warning-text">Warning text</Text>
|
||||
<FieldContainer
|
||||
hasError={!!tokenError}
|
||||
errorMessage={tokenError}
|
||||
removeMargin
|
||||
>
|
||||
<TextInput
|
||||
value={token}
|
||||
scale
|
||||
placeholder="Enter developer token"
|
||||
type={InputType.text}
|
||||
size={InputSize.base}
|
||||
onChange={onChange}
|
||||
maxLength={10000}
|
||||
hasError={!!tokenError}
|
||||
/>
|
||||
</FieldContainer>
|
||||
</StyledContainer>
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
@ -107,7 +153,7 @@ const GenerateDeveloperTokenDialog = ({
|
||||
primary
|
||||
scale
|
||||
onClick={onRevoke}
|
||||
isDisabled={!token}
|
||||
isDisabled={!token || !isValidToken}
|
||||
isLoading={requestRunning}
|
||||
size={ButtonSize.small}
|
||||
/>
|
||||
|
@ -12,6 +12,7 @@ import {
|
||||
TConsentData,
|
||||
TConsentList,
|
||||
TGenerateDeveloperToken,
|
||||
TIntrospectDeveloperToken,
|
||||
} from "../../utils/oauth/types";
|
||||
|
||||
export const getClient = async (clientId: string): Promise<IClientProps> => {
|
||||
@ -273,3 +274,14 @@ export const revokeDeveloperToken = (
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
||||
export const introspectDeveloperToken = (token: string) => {
|
||||
const params = new URLSearchParams();
|
||||
params.append("token", token);
|
||||
|
||||
return request<TIntrospectDeveloperToken>(
|
||||
{ method: "post", url: "/oauth2/introspect", data: params },
|
||||
false,
|
||||
true,
|
||||
);
|
||||
};
|
||||
|
@ -157,3 +157,19 @@ export type TGenerateDeveloperToken = {
|
||||
scope: string;
|
||||
token_type: string;
|
||||
};
|
||||
|
||||
export type TIntrospectDeveloperToken = {
|
||||
active: boolean;
|
||||
sub: string;
|
||||
aud: string[];
|
||||
nbf: string;
|
||||
scope: string;
|
||||
iss: string;
|
||||
exp: number;
|
||||
iat: number;
|
||||
jti: string;
|
||||
tid: number;
|
||||
cid: string;
|
||||
client_id: string;
|
||||
token_type: string;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user