インスタンスURLのバリデーション
This commit is contained in:
parent
9d7f78856d
commit
9cc696f87a
6 changed files with 43 additions and 11 deletions
|
@ -29,7 +29,17 @@ router.get('/login', async ctx => {
|
|||
return;
|
||||
}
|
||||
|
||||
const meta = await api<{ name: string, uri: string, version: string, features: Record<string, boolean | undefined> }>(host, 'meta', {});
|
||||
// http://, https://を潰す
|
||||
host = host.trim().replace(/^https?:\/\//g, '').replace(/\/+/g, '');
|
||||
|
||||
const meta = await api<{ name: string, uri: string, version: string, features: Record<string, boolean | undefined> }>(host, 'meta', {}).catch(async e => {
|
||||
if (!(e instanceof Error && e.name === 'Error')) throw e;
|
||||
await die(ctx, 'hostNotFound');
|
||||
});
|
||||
|
||||
// NOTE: catchが呼ばれた場合はvoidとなるためundefinedのはず
|
||||
if (typeof meta === 'undefined') return;
|
||||
|
||||
if (typeof meta !== 'object') {
|
||||
await die(ctx, 'other');
|
||||
return;
|
||||
|
@ -40,9 +50,6 @@ router.get('/login', async ctx => {
|
|||
return;
|
||||
}
|
||||
|
||||
// ホスト名の正規化
|
||||
host = meta.uri.replace(/^https?:\/\//, '');
|
||||
|
||||
const { name, permission, description } = misskeyAppInfo;
|
||||
|
||||
if (meta.features.miauth) {
|
||||
|
|
|
@ -5,6 +5,8 @@ export const errorCodes = [
|
|||
'tokenRequired',
|
||||
'invalidParamater',
|
||||
'notAuthorized',
|
||||
'hostNotFound',
|
||||
'invalidHostFormat',
|
||||
'other',
|
||||
] as const;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { BrowserRouter, useLocation } from 'react-router-dom';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { BrowserRouter, Link, useLocation } from 'react-router-dom';
|
||||
import { Provider, useDispatch } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
|
@ -22,7 +22,18 @@ const AppInner : React.VFC = () => {
|
|||
|
||||
const {t} = useTranslation();
|
||||
|
||||
const error = (window as any).__misshaialert?.error;
|
||||
const [error, setError] = useState<any>((window as any).__misshaialert?.error);
|
||||
|
||||
// ページ遷移がまだされていないかどうか
|
||||
const [isFirstView, setFirstView] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
if (isFirstView) {
|
||||
setFirstView(false);
|
||||
} else if (!isFirstView && error) {
|
||||
setError(null);
|
||||
}
|
||||
}, [$location]);
|
||||
|
||||
useEffect(() => {
|
||||
const qMobile = window.matchMedia(`(max-width: ${BREAKPOINT_SM})`);
|
||||
|
@ -47,6 +58,7 @@ const AppInner : React.VFC = () => {
|
|||
{t('_error.additionalInfo')}
|
||||
{t(`_error.${error}`)}
|
||||
</p>
|
||||
<Link to="/" className="btn primary">{t('retry')}</Link>
|
||||
</div>
|
||||
) : <Router />}
|
||||
<footer className="text-center pa-5">
|
||||
|
|
|
@ -11,6 +11,10 @@ export const LoginForm: React.VFC = () => {
|
|||
const [host, setHost] = useState('');
|
||||
const {t} = useTranslation();
|
||||
|
||||
const login = () => {
|
||||
location.href = `//${location.host}/login?host=${encodeURIComponent(host)}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<nav>
|
||||
<div>
|
||||
|
@ -21,14 +25,18 @@ export const LoginForm: React.VFC = () => {
|
|||
className="input-field"
|
||||
type="text"
|
||||
value={host}
|
||||
placeholder={t('instanceUrlPlaceholder')}
|
||||
onChange={(e) => setHost(e.target.value)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter') login();
|
||||
}}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
className={!host ? 'btn' : 'btn primary'}
|
||||
style={{ width: 128 }}
|
||||
disabled={!host}
|
||||
onClick={() => location.href = `//${location.host}/login?host=${encodeURIComponent(host)}`}
|
||||
onClick={login}
|
||||
>
|
||||
{t('login')}
|
||||
</button>
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
"update": "更新する",
|
||||
"shareMisskeyTools": "#MisskeyTools をシェアする",
|
||||
"shareMisskeyToolsNote": "#MisskeyTools はいいぞ\n\nhttps://misskey.tools",
|
||||
"instanceUrlPlaceholder": "例:misskey.io",
|
||||
"_sidebar": {
|
||||
"dashboard": "ダッシュボード",
|
||||
"tools": "ツール",
|
||||
|
@ -158,7 +159,8 @@
|
|||
"tokenRequired": "トークンがありません。",
|
||||
"invalidParameter": "パラメータが不正です。",
|
||||
"notAuthorized": "権限がありません。",
|
||||
"other": "なし"
|
||||
"hostNotFound": "インスタンスに接続できませんでした。ホスト名が正しく入力されているか、接続先のインスタンスが正常に動作しているかご確認ください。",
|
||||
"other": "不明なエラーです。"
|
||||
},
|
||||
"_sendTest": {
|
||||
"title": "アラートをテスト送信しますか?",
|
||||
|
|
|
@ -14,6 +14,7 @@ import { Skeleton } from '../../components/Skeleton';
|
|||
import './misshai.scss';
|
||||
import { Ranking } from '../../components/Ranking';
|
||||
import { useTitle } from '../../hooks/useTitle';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
const variables = [
|
||||
'notesCount',
|
||||
|
@ -236,8 +237,8 @@ export const MisshaiPage: React.VFC = () => {
|
|||
<div className="card misshaiRanking">
|
||||
<div className="body">
|
||||
<h1><i className="bi bi-bar-chart"></i> {t('_missHai.ranking')}</h1>
|
||||
<Ranking limit={limit} />
|
||||
{limit && <button className="btn primary" onClick={() => setLimit(undefined)}>{t('_missHai.showAll')}</button>}
|
||||
<Ranking limit={10} />
|
||||
<Link to="/apps/miss-hai/ranking" className="btn primary" onClick={() => setLimit(undefined)}>{t('_missHai.showAll')}</Link>
|
||||
<label className="input-check mt-2">
|
||||
<input type="checkbox" checked={draft.useRanking} onChange={(e) => {
|
||||
updateSetting({ useRanking: e.target.checked });
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue