mirror of
https://github.com/verdaccio/verdaccio.git
synced 2024-12-16 21:56:25 -05:00
wip login web
This commit is contained in:
parent
fbcc36fbb6
commit
fd0c6354a6
2 changed files with 117 additions and 0 deletions
|
@ -1,3 +1,4 @@
|
|||
import bodyParser from 'body-parser';
|
||||
import express, { Router } from 'express';
|
||||
|
||||
import { Auth } from '@verdaccio/auth';
|
||||
|
@ -18,6 +19,7 @@ import publish from './publish';
|
|||
import search from './search';
|
||||
import stars from './stars';
|
||||
import user from './user';
|
||||
import login from './v1/login';
|
||||
import profile from './v1/profile';
|
||||
import v1Search from './v1/search';
|
||||
import token from './v1/token';
|
||||
|
@ -44,6 +46,8 @@ export default function (config: Config, auth: Auth, storage: Storage): Router {
|
|||
app.use(auth.apiJWTmiddleware());
|
||||
app.use(express.json({ strict: false, limit: config.max_body_size || '10mb' }));
|
||||
app.use(antiLoop(config));
|
||||
// TODO : to be removed once we have a react login route
|
||||
app.use(bodyParser.urlencoded({ extended: true }));
|
||||
// encode / in a scoped package name to be matched as a single parameter in routes
|
||||
app.use(encodeScopePackage);
|
||||
// for "npm whoami"
|
||||
|
@ -54,6 +58,7 @@ export default function (config: Config, auth: Auth, storage: Storage): Router {
|
|||
distTags(app, auth, storage);
|
||||
publish(app, auth, storage);
|
||||
ping(app);
|
||||
login(app, auth, storage, config);
|
||||
stars(app, storage);
|
||||
v1Search(app, auth, storage);
|
||||
token(app, auth, storage, config);
|
||||
|
|
112
packages/api/src/v1/login.ts
Normal file
112
packages/api/src/v1/login.ts
Normal file
|
@ -0,0 +1,112 @@
|
|||
import { randomUUID } from 'crypto';
|
||||
import { Request, Response, Router } from 'express';
|
||||
import { isUUID } from 'validator';
|
||||
|
||||
import { Auth, getApiToken } from '@verdaccio/auth';
|
||||
import { createRemoteUser } from '@verdaccio/config';
|
||||
import { HEADERS, HTTP_STATUS, errorUtils } from '@verdaccio/core';
|
||||
import { Storage } from '@verdaccio/store';
|
||||
import { Config, RemoteUser } from '@verdaccio/types';
|
||||
import { getAuthenticatedMessage } from '@verdaccio/utils';
|
||||
|
||||
import { $NextFunctionVer } from '../../types/custom';
|
||||
|
||||
function addNpmLoginApi(route: Router, auth: Auth, storage: Storage, config: Config): void {
|
||||
route.post('/-/v1/login', function (req: Request, res: Response): void {
|
||||
const sessionId = randomUUID();
|
||||
res.status(200).json({
|
||||
loginUrl: 'http://localhost:8000/-/v1/login/cli/' + sessionId,
|
||||
doneUrl: 'http://localhost:8000/-/v1/done?sessionId=' + sessionId,
|
||||
});
|
||||
});
|
||||
route.get('/-/v1/done', function (req: Request, res: Response): void {
|
||||
if (!req.query.sessionId) {
|
||||
res.status(400).json({ error: 'missing session id' });
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionId = req.query.sessionId.toString();
|
||||
if (!isUUID(sessionId, 4)) {
|
||||
res.status(400).json({ error: 'invalid session id' });
|
||||
return;
|
||||
}
|
||||
// const tokens = storage.readTokens();
|
||||
// TODO : check if the token have been created in storage with the sessionId as key
|
||||
const ready = false;
|
||||
|
||||
if (!ready) {
|
||||
// TODO : variable retry-after should be configurable in the config
|
||||
res.header('retry-after', '5');
|
||||
res.status(202).json({});
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ token: 'sample_token_not working' });
|
||||
});
|
||||
|
||||
route.get('/-/v1/login/cli/:sessionId', function (req: Request, res: Response): void {
|
||||
// TODO : This should be a webUI route but i dunno how to do it with React
|
||||
res.send(`
|
||||
<form action="/-/v1/login/cli/${req.params.sessionId}" method="post">
|
||||
<label for="username">Username:</label>
|
||||
<input type="text" id="username" name="username" required><br><br>
|
||||
<label for="password">Password:</label>
|
||||
<input type="password" id="password" name="password" required><br><br>
|
||||
<input type="submit" value="Login">
|
||||
</form>
|
||||
`);
|
||||
});
|
||||
|
||||
route.post(
|
||||
'/-/v1/login/cli/:sessionId',
|
||||
async function (req: Request, res: Response, next: $NextFunctionVer): Promise<void> {
|
||||
const { username, password } = req.body;
|
||||
|
||||
if (!req.params.sessionId) {
|
||||
res.status(400).json({ error: 'missing session id' });
|
||||
return;
|
||||
}
|
||||
|
||||
const sessionId = req.params.sessionId.toString();
|
||||
if (!isUUID(sessionId, 4)) {
|
||||
res.status(400).json({ error: 'invalid session id' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform authentication logic here
|
||||
auth.authenticate(
|
||||
username,
|
||||
password,
|
||||
async function callbackAuthenticate(err, user): Promise<void> {
|
||||
if (err) {
|
||||
return next(errorUtils.getCode(HTTP_STATUS.UNAUTHORIZED, err.message));
|
||||
}
|
||||
|
||||
const restoredRemoteUser: RemoteUser = createRemoteUser(username, user?.groups || []);
|
||||
const token = await getApiToken(auth, config, restoredRemoteUser, password);
|
||||
|
||||
if (!token) {
|
||||
return next(errorUtils.getUnauthorized());
|
||||
}
|
||||
|
||||
res.status(HTTP_STATUS.CREATED);
|
||||
res.set(HEADERS.CACHE_CONTROL, 'no-cache, no-store');
|
||||
|
||||
const message = getAuthenticatedMessage(restoredRemoteUser.name ?? '');
|
||||
// TODO : save the token in storage with the sessionId as key
|
||||
await storage.saveToken({
|
||||
user: restoredRemoteUser.name as string,
|
||||
token: token,
|
||||
key: sessionId,
|
||||
readonly: false,
|
||||
created: '',
|
||||
});
|
||||
return next({
|
||||
ok: message,
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export default addNpmLoginApi;
|
Loading…
Reference in a new issue