Compare commits

...

10 Commits

Author SHA1 Message Date
Kumkwats
6c20416a83 ARView 2023-02-08 09:17:15 +01:00
1415da72df Update Request 2022-11-06 18:46:00 +01:00
0bb28ce89a
update + schema validate 2022-11-06 18:40:30 +01:00
5c21712344
body length 2022-11-02 20:36:13 +01:00
82d356ef5e
better errors + better tools 2022-10-30 19:35:35 +01:00
46a7e07b86
Windaude 2022-10-28 15:47:15 +02:00
Kumkwats
fd335ce5cd added camera view behind 3D view 2022-10-28 15:24:39 +02:00
a4f5cf18d8 Init requests 2022-10-26 21:47:56 +02:00
e9e1b48970
insomnia folder 2022-10-26 21:43:05 +02:00
0f53063832
better errors 2022-10-26 00:16:41 +02:00
42 changed files with 2125 additions and 174 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@
**/config
!.prettierrc.json
!.insomnia

View File

@ -0,0 +1,8 @@
_id: spc_8436777c430547adb1085fd68e18eace
type: ApiSpec
parentId: wrk_01922deddc7342ddb4d070126530214b
modified: 1666813426216
created: 1666813426216
fileName: Rate
contents: ""
contentType: yaml

View File

@ -0,0 +1,14 @@
_id: env_25eaa5dc66424aeabb57ef52fb713da8
type: Environment
parentId: env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a
modified: 1666813483038
created: 1666813431942
name: local
data:
URL: http://localhost:8000
dataPropertyOrder:
"&":
- URL
color: null
isPrivate: false
metaSortKey: 1666813431942

View File

@ -0,0 +1,14 @@
_id: env_589a320c58d54efc8e9ab96f6506ebd0
type: Environment
parentId: env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a
modified: 1666813482405
created: 1666813453631
name: yayeet.cf
data:
URL: https://html5.yayeet.cf/api
dataPropertyOrder:
"&":
- URL
color: null
isPrivate: false
metaSortKey: 1666813453631

View File

@ -0,0 +1,11 @@
_id: env_9b022c4edb1e6f6aa558cd2b00817d97d73ac78a
type: Environment
parentId: wrk_01922deddc7342ddb4d070126530214b
modified: 1666813430220
created: 1666813426222
name: Base Environment
data: {}
dataPropertyOrder: {}
color: null
isPrivate: false
metaSortKey: 1666813426222

View File

@ -0,0 +1,21 @@
_id: req_7a775a1b9142457eb390ccd6b2e72f28
type: Request
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
modified: 1666813549000
created: 1666813535408
url: "{{ _.URL }}/user/logout"
name: Logout
description: ""
method: POST
body: {}
parameters: []
headers: []
authentication: {}
metaSortKey: -1666813492452
isPrivate: false
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global

View File

@ -0,0 +1,30 @@
_id: req_b0a828e3ee4d4267bd036b10d6bb1bed
type: Request
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
modified: 1667756731637
created: 1666813566609
url: "{{ _.URL }}/user/create"
name: Create
description: ""
method: POST
body:
mimeType: application/json
text: |-
{
"username": "test2",
"password": "coucou",
"role": "USER"
}
parameters: []
headers:
- name: Content-Type
value: application/json
authentication: {}
metaSortKey: -1666813492352
isPrivate: false
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global

View File

@ -0,0 +1,21 @@
_id: req_bf97a9e369584040ac3a8440c7b2bc7c
type: Request
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
modified: 1666813598408
created: 1666813551357
url: "{{ _.URL }}/user/read/ff08bc79-ba76-432d-9709-34eefbc462eb"
name: Read
description: ""
method: GET
body: {}
parameters: []
headers: []
authentication: {}
metaSortKey: -1666813492402
isPrivate: false
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global

View File

@ -0,0 +1,30 @@
_id: req_dbbe63eee56d439bb93f4c4929fcbfb2
type: Request
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
modified: 1667756736645
created: 1666813492501
url: "{{ _.URL }}/user/login/"
name: Login
description: ""
method: POST
body:
mimeType: application/json
text: |-
{
"username": "admin",
"password": "motdepasse"
}
parameters: []
headers:
- name: Content-Type
value: application/json
id: pair_32919a49053545f5b23698f4c5724a56
authentication: {}
metaSortKey: -1666813492502
isPrivate: false
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global

View File

@ -0,0 +1,28 @@
_id: req_f2d435a1ee5b47b1b7b6e2be9db8a8bb
type: Request
parentId: fld_c78e326c656f4411b8899877dd4f3b9c
modified: 1667756731065
created: 1667753525832
url: "{{ _.URL }}/user/update/ff08bc79-ba76-432d-9709-34eefbc462eb"
name: Update
description: ""
method: PATCH
body:
mimeType: application/json
text: |-
{
"username": "admin2"
}
parameters: []
headers:
- name: Content-Type
value: application/json
authentication: {}
metaSortKey: -1666813492302
isPrivate: false
settingStoreCookies: true
settingSendCookies: true
settingDisableRenderRequestBody: false
settingEncodeUrl: true
settingRebuildPath: true
settingFollowRedirects: global

View File

@ -0,0 +1,10 @@
_id: fld_c78e326c656f4411b8899877dd4f3b9c
type: RequestGroup
parentId: wrk_01922deddc7342ddb4d070126530214b
modified: 1666813489256
created: 1666813489256
name: User
description: ""
environment: {}
environmentPropertyOrder: null
metaSortKey: -1666813489256

View File

@ -0,0 +1,8 @@
_id: wrk_01922deddc7342ddb4d070126530214b
type: Workspace
parentId: null
modified: 1666813426216
created: 1666813426216
name: Rate
description: ""
scope: design

View File

@ -1,19 +1,19 @@
import './paths';
import Server from './framework/express/server';
import ip from 'ip';
import UserModel from './framework/mongo/user';
import { MongoClient } from 'mongodb';
import ip from 'ip';
import Server from './framework/express/server';
import UserModel from './framework/mongo/user';
import { Config } from './config';
import { exit, env } from 'process';
export type Services = {
userModel: UserModel;
};
const configFile = env.CONFIGFILE;
const configFile = process.env.CONFIGFILE;
if (configFile === undefined) {
console.log('env var CONFIGFILE not set');
exit(1);
process.exit(1);
}
const config = new Config(configFile);
@ -27,6 +27,13 @@ const services: Services = {
const server = new Server(config.server, config.mongo, services);
process.on('SIGINT', async () => {
console.log('\nClosing Api...');
await mongo.close();
await server.close();
process.exit();
});
server.start(() =>
console.log(
`Running on http://127.0.0.1:${config.server.port} http://${ip.address()}:${

View File

@ -16,6 +16,15 @@ export class Config {
constructor(configFile: string) {
const config = JSON.parse(readFileSync(configFile).toString()) as Config;
if (
config.mongo.dbName === undefined ||
config.mongo.uri === undefined ||
config.server.origin === undefined ||
config.server.port === undefined
) {
console.log('Error in Config File');
process.exit(1);
}
this.server = config.server;
this.mongo = config.mongo;
}

View File

@ -5,7 +5,7 @@ import {
UserRoles,
UserWithPasswordCtor,
} from '@core';
import { generateHash } from '../functions/password';
import { getHashedPassword } from '../functions/password';
import { Entity } from './entity';
export class User extends Entity implements UserInfo {
@ -34,7 +34,7 @@ export class UserWithPassword extends User implements UserInfoWithPassword {
constructor(raw: UserWithPasswordCtor) {
super(raw);
this.password = generateHash(this.uuid, raw.password || '');
this.password = getHashedPassword(this.uuid, raw.password || '');
}
Info(): UserInfoWithPassword {

View File

@ -1,6 +1,6 @@
import { ErrorRequestHandler, Request, RequestHandler } from 'express';
import { randomUUID } from 'crypto';
import { validationResult } from 'express-validator';
import { validationResult, matchedData } from 'express-validator';
import { UserInfo, UserRoles } from '@core';
declare module 'express-session' {
@ -9,22 +9,22 @@ declare module 'express-session' {
}
}
export function getId(req: Request): string {
return req.header('request-id') || 'unknown';
export function getRequestId(req: Request): string {
return req.header('x-request-id') || 'unknown';
}
export function RequestId(): RequestHandler {
return (req, res, next) => {
req.headers['request-id'] = randomUUID();
req.headers['x-request-id'] = randomUUID();
next();
};
}
export function CheckPermissions(): RequestHandler {
function getResourceId(req: Request): string | null {
function getResourceId(req: Request): string | undefined {
if (req.params.uuid) return req.params.uuid;
if (req.body.uuid) return req.body.uuid;
return null;
return undefined;
}
function canAccessRessource(user: UserInfo, uuid: string): boolean {
@ -34,35 +34,39 @@ export function CheckPermissions(): RequestHandler {
return (req, res, next) => {
if (!req.session.user) {
next({ status: 401, messsage: 'Unauthorized' });
return;
return next({ status: 401, messsage: 'Unauthorized' });
}
if (req.session.user.role === UserRoles.ADMIN) {
next();
return;
return next();
}
const ressourceId = getResourceId(req);
if (!ressourceId) {
next({ status: 403, messsage: 'Forbidden' });
return;
}
if (canAccessRessource(req.session.user, ressourceId)) {
next();
return;
} else {
next({ status: 403, messsage: 'Forbidden' });
return;
return next({ status: 403, messsage: 'Forbidden' });
}
next({ status: 401, messsage: 'Unauthorized' });
if (canAccessRessource(req.session.user, ressourceId)) {
return next();
}
next({ status: 403, messsage: 'Forbidden' });
};
}
export function SchemaValidator(): RequestHandler {
export function ValidateSchema(): RequestHandler {
return (req, res, next) => {
const error = validationResult(req);
const oldBody = req.body;
req.body = matchedData(req, { locations: ['body'] });
if (JSON.stringify(oldBody) !== JSON.stringify(req.body))
return next({
status: 422,
message: 'Unprocessable Entity',
});
error.isEmpty()
? next()
: next({
@ -76,6 +80,6 @@ export function ErrorHandler(): ErrorRequestHandler {
return (error, req, res, next) => {
error.status
? res.status(error.status).send(error)
: res.status(500).send(error);
: res.status(500).send({ status: 500, message: error.message });
};
}

View File

@ -36,3 +36,21 @@ export const CreateUserSchema = () =>
},
},
});
export const UpdateUserSchema = () =>
checkSchema({
username: {
isString: true,
optional: true,
},
password: {
isString: true,
optional: true,
},
role: {
isIn: {
options: [Object.values(UserRoles)],
},
optional: true,
},
});

View File

@ -1,15 +1,18 @@
import express, { Express } from 'express';
import cors from 'cors';
import session from 'express-session';
import MongoStore from 'connect-mongo';
import { randomUUID } from 'crypto';
import * as http from 'http';
import { Routes } from './router';
import { RequestId, ErrorHandler } from './middleware';
import { Services } from '../../app';
import { MongoConfig, ServerConfig } from '../../config';
import { randomUUID } from 'crypto';
import MongoStore from 'connect-mongo';
class Server {
private app: Express;
private server: http.Server;
private config: ServerConfig;
constructor(
@ -20,6 +23,7 @@ class Server {
this.config = config;
this.app = express();
this.app.disable('x-powered-by');
this.app.use(express.json());
this.app.use(
cors({
@ -53,7 +57,16 @@ class Server {
}
start(func: () => void): void {
this.app.listen(this.config.port, func);
this.server = this.app.listen(this.config.port, func);
}
async close(): Promise<void> {
return new Promise<void>((resolve, reject) => {
this.server.close((error) => {
if (error) reject(error);
resolve();
});
});
}
}

View File

@ -1,23 +1,31 @@
import { RequestHandler, Router } from 'express';
import { Services } from '../../app';
import { CreateUser, ReadUser, LoginUser } from '../../functions/user';
import {
CreateUser,
ReadUser,
LoginUser,
UpdateUser,
} from '../../functions/user';
import {
LoginUserSchema,
CreateUserSchema,
ReadUserSchema,
LogoutUserSchema,
UpdateUserSchema,
} from './schema/user';
import { CheckPermissions, getId, SchemaValidator } from './middleware';
import { CheckPermissions, getRequestId, ValidateSchema } from './middleware';
function LoginHandler(services: Services): RequestHandler {
const login = LoginUser(services);
return async (req, res, next) => {
const user = await login(getId(req), req.body);
user ? (req.session.user = user) : (req.session.user = null);
user
? res.status(200).send(user)
: next({ status: 401, message: 'wrong username or password' });
try {
const user = await login(getRequestId(req), req.body);
user ? (req.session.user = user) : (req.session.user = null);
res.status(200).send(user);
} catch (error) {
next({ status: 401, message: 'wrong username or password' });
}
};
}
@ -27,7 +35,7 @@ function LogoutHandler(services: Services): RequestHandler {
req.session.user = null;
res.status(204).send();
} else {
next({ status: 401, message: 'not logged in' });
next({ status: 401, message: 'Not Logged In' });
}
};
}
@ -36,8 +44,12 @@ function CreateHandler(services: Services): RequestHandler {
const createUser = CreateUser(services);
return async (req, res, next) => {
const user = await createUser(getId(req), req.body);
user ? res.status(201).send(user) : next();
try {
const user = await createUser(getRequestId(req), req.body);
res.status(201).send(user);
} catch (error) {
next({ status: 409, message: 'User Already Exists' });
}
};
}
@ -45,10 +57,29 @@ function ReadHandler(services: Services): RequestHandler {
const readUser = ReadUser(services);
return async (req, res, next) => {
const user = await readUser(getId(req), req.params.uuid);
user
? res.status(200).send(user)
: next({ status: 404, message: 'user not found' });
try {
const user = await readUser(getRequestId(req), req.params.uuid);
res.status(200).send(user);
} catch (error) {
next({ status: 404, message: 'User Not Found' });
}
};
}
function UpdateHandler(services: Services): RequestHandler {
const updateUser = UpdateUser(services);
return async (req, res, next) => {
try {
const user = await updateUser(
getRequestId(req),
req.params.uuid,
req.body,
);
res.status(200).send(user);
} catch (error) {
next({ status: 404, message: 'User Not Found' });
}
};
}
@ -58,30 +89,38 @@ export function Routes(services: Services) {
router.post(
'/login',
LoginUserSchema(),
SchemaValidator(),
ValidateSchema(),
LoginHandler(services),
);
router.post(
'/logout',
LogoutUserSchema(),
SchemaValidator(),
ValidateSchema(),
LogoutHandler(services),
);
router.get(
'/read/:uuid',
ReadUserSchema(),
SchemaValidator(),
CheckPermissions(),
ReadUserSchema(),
ValidateSchema(),
ReadHandler(services),
);
router.post(
'/create',
CreateUserSchema(),
SchemaValidator(),
CheckPermissions(),
CreateUserSchema(),
ValidateSchema(),
CreateHandler(services),
);
router.patch(
'/update/:uuid',
CheckPermissions(),
UpdateUserSchema(),
ValidateSchema(),
UpdateHandler(services),
);
return router;
}

View File

@ -1,8 +1,8 @@
import { Collection, Db } from 'mongodb';
import { LoginUserBody } from '../../../../core/src/user';
import { LoginUserBody, UpdateUserBody } from '@core';
import { User, UserWithPassword } from '../../entities/user';
import log from '../../functions/logger';
import { generateHash } from '../../functions/password';
import { log } from '../../functions/logger';
import { getHashedPassword } from '../../functions/password';
class UserModel {
private collection: Collection<User>;
@ -11,42 +11,87 @@ class UserModel {
this.collection = db.collection<User>('users');
}
public async login(tracker: string, data: LoginUserBody) {
public async login(tracker: string, data: LoginUserBody): Promise<User> {
const checkUser = await this.collection.findOne({
username: data.username,
});
if (checkUser === null) {
if (!checkUser) {
log(tracker, 'User Not Found');
return null;
throw new Error();
}
const user = await this.collection.findOne({
const userDocument = await this.collection.findOne({
uuid: checkUser.uuid,
password: generateHash(checkUser.uuid, data.password),
password: getHashedPassword(checkUser.uuid, data.password),
});
if (user === null) {
if (!userDocument) {
log(tracker, 'Wrong Password');
return null;
throw new Error();
}
const user = new User(userDocument);
log(tracker, 'LOG IN', user);
return new User(user);
return user;
}
public async create(tracker: string, user: UserWithPassword) {
await this.collection.insertOne(user);
log(tracker, 'CREATE USER', user);
return this.read(tracker, user.uuid);
}
public async read(tracker: string, uuid: string) {
const user = await this.collection.findOne({ uuid });
if (user === null) {
log(tracker, 'User Not Found');
return null;
public async create(
tracker: string,
userInfo: UserWithPassword,
): Promise<User> {
const checkUser = await this.collection.findOne({
username: userInfo.username,
});
if (checkUser) {
log(tracker, 'User Already Exists');
throw new Error();
}
await this.collection.insertOne(userInfo);
const user = await this.read(tracker, userInfo.uuid);
log(tracker, 'CREATE USER', user);
return user;
}
public async read(tracker: string, uuid: string): Promise<User> {
const userDocument = await this.collection.findOne({ uuid });
if (!userDocument) {
log(tracker, 'User Not Found');
throw new Error();
}
const user = new User(userDocument);
log(tracker, 'READ USER', user);
return new User(user);
return user;
}
public async update(
tracker: string,
uuid: string,
userInfo: UpdateUserBody,
): Promise<User> {
const checkUser = await this.collection.findOne({ uuid });
if (!checkUser) {
log(tracker, 'User Does Not Exist');
throw new Error();
}
if (userInfo.password)
userInfo.password = getHashedPassword(uuid, userInfo.password);
await this.collection.updateOne(
{ uuid },
{
$set: {
...userInfo,
updatedAt: new Date(),
},
},
);
const user = await this.read(tracker, uuid);
log(tracker, 'UPDATE USER', user);
return user;
}
}

View File

@ -1,11 +1,10 @@
export function log(tracker: string, ...message: unknown[]) {
message.forEach((obj, index) => {
try {
message[index] = JSON.stringify(obj);
} catch {}
});
if (message)
message.forEach((obj, index) => {
try {
message[index] = JSON.stringify(obj);
} catch {}
});
tracker ? console.log(`[${tracker}]`, ...message) : console.log(...message);
message ? console.log(`[${tracker}]`, ...message) : console.log(tracker);
}
export default log;

View File

@ -1,5 +1,9 @@
import { createHash } from 'crypto';
export function getHashedPassword(uuid: string, password: string) {
return generateHash(uuid, password);
}
export function generateHash(...values: string[]) {
return createHash('sha256').update(values.join('')).digest('hex');
}

View File

@ -1,36 +1,47 @@
import { CreateUserBody, LoginUserBody, UserInfo } from '@core';
import { CreateUserBody, LoginUserBody, UserInfo, UpdateUserBody } from '@core';
import { Services } from '../app';
import { UserWithPassword } from '../entities/user';
export function LoginUser(
services: Services,
): (tracker: string, raw: LoginUserBody) => Promise<UserInfo | null> {
): (tracker: string, raw: LoginUserBody) => Promise<UserInfo> {
const { userModel } = services;
return async (tracker, raw) => {
const user = await userModel.login(tracker, raw);
return user ? user.Info() : null;
return user.Info();
};
}
export function CreateUser(
services: Services,
): (tracker: string, raw: CreateUserBody) => Promise<UserInfo | null> {
): (tracker: string, raw: CreateUserBody) => Promise<UserInfo> {
const { userModel } = services;
return async (tracker, raw) => {
const user = await userModel.create(tracker, new UserWithPassword(raw));
return user ? user.Info() : null;
return user.Info();
};
}
export function ReadUser(
services: Services,
): (tracker: string, uuid: string) => Promise<UserInfo | null> {
): (tracker: string, uuid: string) => Promise<UserInfo> {
const { userModel } = services;
return async (tracker, uuid) => {
const user = await userModel.read(tracker, uuid);
return user ? user.Info() : null;
return user.Info();
};
}
export function UpdateUser(
services: Services,
): (tracker: string, uuid: string, raw: UpdateUserBody) => Promise<UserInfo> {
const { userModel } = services;
return async (tracker, uuid, raw) => {
const user = await userModel.update(tracker, uuid, raw);
return user.Info();
};
}

View File

@ -29,6 +29,8 @@ export type CreateUserBody = {
role: keyof typeof UserRoles;
};
export type UpdateUserBody = Partial<Omit<UserInfoWithPassword, 'uuid'>>;
export type LoginUserBody = {
username: string;
password: string;

0
scripts/deploy.sh Executable file → Normal file
View File

26
scripts/tools.py Executable file → Normal file
View File

@ -1,6 +1,8 @@
#!/usr/bin/python
import os
import sys
from os import chdir, path
from sys import argv
from subprocess import run, PIPE
from multiprocessing import Process
apps = ['core', 'api', 'www']
commands = {
@ -14,19 +16,29 @@ def print_commands():
print('Available commands:', [c for c in commands])
def run_command_in_app(app: str, command: str):
chdir(app)
result = run(command.split(' '), stdout=PIPE, stderr=PIPE, text=True)
status = 'DONE' if result.returncode == 0 else 'ERROR'
print('%s:\t%s' % (app, status))
if status == 'ERROR':
print(result.stdout, result.stderr)
if __name__ == '__main__':
if len(sys.argv) < 2:
if len(argv) < 2:
print_commands()
exit()
cmd = sys.argv[1]
cmd = argv[1]
if cmd not in commands:
print('Command \'%s\' not available' % cmd)
print_commands()
exit()
chdir(path.join(path.dirname(path.realpath(__file__)), '..'))
print('Running \'%s\' on %d apps: %s' % (commands[cmd], len(apps), apps))
for app in apps:
os.chdir(app)
os.system(commands[cmd])
os.chdir('..')
Process(target=run_command_in_app, args=(app, commands[cmd])).start()

1282
www/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@
"author": "Yanis Rigaudeau - Axel Barault",
"private": true,
"scripts": {
"build": "rollup -c",
"build": "rollup -c --failAfterWarnings",
"dev": "rollup -c -w",
"start": "sirv public --no-clear --host --single",
"check": "svelte-check --tsconfig ./tsconfig.json",
@ -18,6 +18,7 @@
"@rollup/plugin-typescript": "^8.0.0",
"@tsconfig/svelte": "^2.0.0",
"@types/three": "^0.144.0",
"@types/w3c-image-capture": "^1.0.7",
"prettier": "^2.7.1",
"prettier-plugin-svelte": "^2.8.0",
"rollup": "^2.3.4",
@ -32,6 +33,7 @@
"typescript": "^4.0.0"
},
"dependencies": {
"@ar-js-org/ar.js": "^3.4.3",
"papercss": "^1.8.3",
"sirv-cli": "^2.0.0",
"spaper": "^0.9.6",

Binary file not shown.

View File

@ -0,0 +1,195 @@
234 235 240 233 240 234 240 235 240 237 240 238 240 240 240 232
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 228
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 239
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
231 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
225 149 240 240 186 216 225 174 240 240 240 237 238 240 240 240
150 107 238 231 75 208 115 147 238 228 223 226 237 180 226 240
150 62 181 213 62 187 113 169 197 72 29 237 120 50 53 207
149 63 47 78 53 184 113 101 142 5 150 150 45 217 186 83
121 84 220 222 58 180 121 92 128 109 237 124 155 232 161 64
149 71 240 240 76 210 98 109 122 108 240 129 51 119 161 155
149 186 240 240 98 219 135 152 207 191 236 227 152 77 175 209
235 235 240 233 240 234 240 235 240 236 240 238 240 240 240 240
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
236 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
225 156 240 240 186 216 225 186 240 240 240 240 240 240 240 240
150 117 240 231 72 206 115 162 240 232 223 237 240 180 226 240
150 74 187 213 51 184 103 168 197 78 29 237 120 50 53 216
144 77 51 74 61 184 106 101 142 5 150 152 52 217 186 85
117 89 219 219 65 184 121 92 128 100 236 125 156 240 170 73
148 71 240 240 76 210 109 109 121 99 240 137 51 120 166 164
140 186 240 240 98 220 150 156 207 192 236 230 152 77 176 212
234 235 240 233 240 234 240 235 240 236 240 238 240 240 240 233
229 240 240 240 240 240 240 240 240 240 240 240 240 240 240 239
227 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
234 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
235 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
232 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
228 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
225 156 240 240 182 212 225 180 240 240 240 240 240 240 240 240
150 116 238 228 66 205 115 151 238 236 225 240 240 180 226 240
156 84 186 211 47 184 109 170 200 92 30 240 120 50 53 216
147 83 51 73 50 184 106 110 148 17 151 150 45 217 186 85
127 98 219 219 58 179 109 101 128 107 237 125 155 240 163 72
155 86 240 240 76 201 85 108 121 95 232 137 51 118 153 155
149 189 240 240 98 220 141 154 206 178 235 230 152 77 175 209
232 228 239 240 240 240 240 240 240 240 240 207 83 64 155 209
240 240 240 240 240 240 240 240 240 240 226 53 186 161 161 175
240 240 240 240 240 240 240 240 240 240 180 50 217 232 119 77
240 240 240 240 240 240 240 240 240 238 237 120 45 155 51 152
238 240 240 240 240 240 240 240 240 237 226 237 150 124 129 227
240 240 240 240 240 240 240 240 240 240 223 29 150 237 240 236
237 240 240 240 240 240 240 240 240 240 228 72 5 109 108 191
240 240 240 240 240 240 240 240 240 240 238 197 142 128 122 207
235 240 240 240 240 240 240 240 240 174 147 169 101 92 109 152
240 240 240 240 240 240 240 240 240 225 115 113 113 121 98 135
234 240 240 240 240 240 240 240 240 216 208 187 184 180 210 219
240 240 240 240 240 240 240 240 240 186 75 62 53 58 76 98
233 240 240 240 240 240 240 240 240 240 231 213 78 222 240 240
240 240 240 240 240 240 240 240 240 240 238 181 47 220 240 240
235 240 240 240 240 240 240 240 240 149 107 62 63 84 71 186
234 229 227 240 236 234 236 231 229 225 150 150 149 121 149 149
240 240 240 240 240 240 240 240 240 240 240 216 85 73 164 212
240 240 240 240 240 240 240 240 240 240 226 53 186 170 166 176
240 240 240 240 240 240 240 240 240 240 180 50 217 240 120 77
240 240 240 240 240 240 240 240 240 240 240 120 52 156 51 152
238 240 240 240 240 240 240 240 240 240 237 237 152 125 137 230
240 240 240 240 240 240 240 240 240 240 223 29 150 236 240 236
236 240 240 240 240 240 240 240 240 240 232 78 5 100 99 192
240 240 240 240 240 240 240 240 240 240 240 197 142 128 121 207
235 240 240 240 240 240 240 240 240 186 162 168 101 92 109 156
240 240 240 240 240 240 240 240 240 225 115 103 106 121 109 150
234 240 240 240 240 240 240 240 240 216 206 184 184 184 210 220
240 240 240 240 240 240 240 240 240 186 72 51 61 65 76 98
233 240 240 240 240 240 240 240 240 240 231 213 74 219 240 240
240 240 240 240 240 240 240 240 240 240 240 187 51 219 240 240
235 240 240 240 240 240 240 240 240 156 117 74 77 89 71 186
235 229 227 240 236 234 236 232 229 225 150 150 144 117 148 140
233 239 240 240 240 240 240 240 240 240 240 216 85 72 155 209
240 240 240 240 240 240 240 240 240 240 226 53 186 163 153 175
240 240 240 240 240 240 240 240 240 240 180 50 217 240 118 77
240 240 240 240 240 240 240 240 240 240 240 120 45 155 51 152
238 240 240 240 240 240 240 240 240 240 240 240 150 125 137 230
240 240 240 240 240 240 240 240 240 240 225 30 151 237 232 235
236 240 240 240 240 240 240 240 240 240 236 92 17 107 95 178
240 240 240 240 240 240 240 240 240 240 238 200 148 128 121 206
235 240 240 240 240 240 240 240 240 180 151 170 110 101 108 154
240 240 240 240 240 240 240 240 240 225 115 109 106 109 85 141
234 240 240 240 240 240 240 240 240 212 205 184 184 179 201 220
240 240 240 240 240 240 240 240 240 182 66 47 50 58 76 98
233 240 240 240 240 240 240 240 240 240 228 211 73 219 240 240
240 240 240 240 240 240 240 240 240 240 238 186 51 219 240 240
235 240 240 240 240 240 240 240 240 156 116 84 83 98 86 189
234 229 227 240 234 232 235 232 228 225 150 156 147 127 155 149
209 175 77 152 227 236 191 207 152 135 219 98 240 240 186 149
155 161 119 51 129 240 108 122 109 98 210 76 240 240 71 149
64 161 232 155 124 237 109 128 92 121 180 58 222 220 84 121
83 186 217 45 150 150 5 142 101 113 184 53 78 47 63 149
207 53 50 120 237 29 72 197 169 113 187 62 213 181 62 150
240 226 180 237 226 223 228 238 147 115 208 75 231 238 107 150
240 240 240 238 237 240 240 240 174 225 216 186 240 240 149 225
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 231
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
239 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
228 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
232 240 240 240 238 240 237 240 235 240 234 240 233 240 235 234
212 176 77 152 230 236 192 207 156 150 220 98 240 240 186 140
164 166 120 51 137 240 99 121 109 109 210 76 240 240 71 148
73 170 240 156 125 236 100 128 92 121 184 65 219 219 89 117
85 186 217 52 152 150 5 142 101 106 184 61 74 51 77 144
216 53 50 120 237 29 78 197 168 103 184 51 213 187 74 150
240 226 180 240 237 223 232 240 162 115 206 72 231 240 117 150
240 240 240 240 240 240 240 240 186 225 216 186 240 240 156 225
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 236
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
240 240 240 240 238 240 236 240 235 240 234 240 233 240 235 235
209 175 77 152 230 235 178 206 154 141 220 98 240 240 189 149
155 153 118 51 137 232 95 121 108 85 201 76 240 240 86 155
72 163 240 155 125 237 107 128 101 109 179 58 219 219 98 127
85 186 217 45 150 151 17 148 110 106 184 50 73 51 83 147
216 53 50 120 240 30 92 200 170 109 184 47 211 186 84 156
240 226 180 240 240 225 236 238 151 115 205 66 228 238 116 150
240 240 240 240 240 240 240 240 180 225 212 182 240 240 156 225
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 228
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 235
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 232
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 234
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 240
240 240 240 240 240 240 240 240 240 240 240 240 240 240 240 227
239 240 240 240 240 240 240 240 240 240 240 240 240 240 240 229
233 240 240 240 238 240 236 240 235 240 234 240 233 240 235 234
149 149 121 149 150 150 225 229 231 236 234 236 240 227 229 234
186 71 84 63 62 107 149 240 240 240 240 240 240 240 240 235
240 240 220 47 181 238 240 240 240 240 240 240 240 240 240 240
240 240 222 78 213 231 240 240 240 240 240 240 240 240 240 233
98 76 58 53 62 75 186 240 240 240 240 240 240 240 240 240
219 210 180 184 187 208 216 240 240 240 240 240 240 240 240 234
135 98 121 113 113 115 225 240 240 240 240 240 240 240 240 240
152 109 92 101 169 147 174 240 240 240 240 240 240 240 240 235
207 122 128 142 197 238 240 240 240 240 240 240 240 240 240 240
191 108 109 5 72 228 240 240 240 240 240 240 240 240 240 237
236 240 237 150 29 223 240 240 240 240 240 240 240 240 240 240
227 129 124 150 237 226 237 240 240 240 240 240 240 240 240 238
152 51 155 45 120 237 238 240 240 240 240 240 240 240 240 240
77 119 232 217 50 180 240 240 240 240 240 240 240 240 240 240
175 161 161 186 53 226 240 240 240 240 240 240 240 240 240 240
209 155 64 83 207 240 240 240 240 240 240 240 240 239 228 232
140 148 117 144 150 150 225 229 232 236 234 236 240 227 229 235
186 71 89 77 74 117 156 240 240 240 240 240 240 240 240 235
240 240 219 51 187 240 240 240 240 240 240 240 240 240 240 240
240 240 219 74 213 231 240 240 240 240 240 240 240 240 240 233
98 76 65 61 51 72 186 240 240 240 240 240 240 240 240 240
220 210 184 184 184 206 216 240 240 240 240 240 240 240 240 234
150 109 121 106 103 115 225 240 240 240 240 240 240 240 240 240
156 109 92 101 168 162 186 240 240 240 240 240 240 240 240 235
207 121 128 142 197 240 240 240 240 240 240 240 240 240 240 240
192 99 100 5 78 232 240 240 240 240 240 240 240 240 240 236
236 240 236 150 29 223 240 240 240 240 240 240 240 240 240 240
230 137 125 152 237 237 240 240 240 240 240 240 240 240 240 238
152 51 156 52 120 240 240 240 240 240 240 240 240 240 240 240
77 120 240 217 50 180 240 240 240 240 240 240 240 240 240 240
176 166 170 186 53 226 240 240 240 240 240 240 240 240 240 240
212 164 73 85 216 240 240 240 240 240 240 240 240 240 240 240
149 155 127 147 156 150 225 228 232 235 232 234 240 227 229 234
189 86 98 83 84 116 156 240 240 240 240 240 240 240 240 235
240 240 219 51 186 238 240 240 240 240 240 240 240 240 240 240
240 240 219 73 211 228 240 240 240 240 240 240 240 240 240 233
98 76 58 50 47 66 182 240 240 240 240 240 240 240 240 240
220 201 179 184 184 205 212 240 240 240 240 240 240 240 240 234
141 85 109 106 109 115 225 240 240 240 240 240 240 240 240 240
154 108 101 110 170 151 180 240 240 240 240 240 240 240 240 235
206 121 128 148 200 238 240 240 240 240 240 240 240 240 240 240
178 95 107 17 92 236 240 240 240 240 240 240 240 240 240 236
235 232 237 151 30 225 240 240 240 240 240 240 240 240 240 240
230 137 125 150 240 240 240 240 240 240 240 240 240 240 240 238
152 51 155 45 120 240 240 240 240 240 240 240 240 240 240 240
77 118 240 217 50 180 240 240 240 240 240 240 240 240 240 240
175 153 163 186 53 226 240 240 240 240 240 240 240 240 240 240
209 155 72 85 216 240 240 240 240 240 240 240 240 240 239 233

View File

@ -1,15 +1,29 @@
<script>
<script lang="ts">
import 'papercss/dist/paper.min.css';
import { onMount } from 'svelte';
import { Router, Route } from 'svelte-navigator';
import Test3D from './pages/test3D.svelte';
import { currentUser } from './store/user';
import { read } from './functions/user';
import ViewAR from './pages/ViewAR.svelte';
import Login from './pages/Login.svelte';
import Profile from './pages/Profile.svelte';
onMount(async () => {
if ($currentUser) {
try {
const user = await read($currentUser.uuid);
currentUser.set(user);
} catch (error) {
currentUser.set(null);
window.location.href = '/';
}
}
});
</script>
<Router>
<Route path="/">
<Test3D />
<ViewAR />
</Route>
<Route path="/login">
<Login />

View File

@ -1,16 +1,13 @@
<script lang="ts">
import NavBar from '../components/NavBar.svelte';
import { beforeUpdate, afterUpdate, onMount, onDestroy } from 'svelte';
import * as Three from 'three';
let container: HTMLElement;
let canvas: HTMLCanvasElement;
let width: number;
let height: number;
export let width: number;
export let height: number;
//#region variables
//let innerWidth: number = 0;
//let innerHeight: number = 0;
let container: HTMLElement;
let canvas: HTMLCanvasElement;
let maxInnerWidth: number = 0;
let maxInnerHeight: number = 0;
@ -18,6 +15,21 @@
let focalLength: number = 540 / Math.atan((70 * Math.PI) / 180);
let fov = 75;
//let baseHorizontalFOV: number = 2.0*Math.atan(baseAspectRation*Math.tan(baseVerticalFOV*0.5));
let scene: Three.Scene = new Three.Scene();
let camera: Three.PerspectiveCamera = new Three.PerspectiveCamera(
75,
1,
0.1,
1000,
);
let renderer: Three.WebGLRenderer = new Three.WebGLRenderer();
let box: Three.BoxGeometry = new Three.BoxGeometry(1, 1, 1);
let mat: Three.MeshBasicMaterial = new Three.MeshBasicMaterial({
color: 0x00ff00,
});
let cube = new Three.Mesh(box, mat);
//#endregion
//#region functions
@ -50,22 +62,6 @@
resetMaxDimensions();
}
}
//#endregion
let scene: Three.Scene = new Three.Scene();
let camera: Three.PerspectiveCamera = new Three.PerspectiveCamera(
75,
1,
0.1,
1000,
);
let renderer: Three.WebGLRenderer = new Three.WebGLRenderer();
let box: Three.BoxGeometry = new Three.BoxGeometry(1, 1, 1);
let mat: Three.MeshBasicMaterial = new Three.MeshBasicMaterial({
color: 0x00ff00,
});
let cube = new Three.Mesh(box, mat);
function animate() {
requestAnimationFrame(animate);
@ -75,6 +71,7 @@
renderer.render(scene, camera);
}
//#endregion
onMount(() => {
canvas = container.appendChild(renderer.domElement);
@ -96,7 +93,7 @@
camera.setViewOffset(width, height, 0, 0, width, height);
renderer.setSize(width, height);
//renderer.setClearColor(0x000000, (innerHeight/(maxInnerHeight))/2 + 0.5);
renderer.setClearColor(0x000000, 0.1);
});
afterUpdate(() => {});
@ -106,17 +103,15 @@
});
</script>
<div
id="container"
bind:this={container}
bind:clientWidth={width}
bind:clientHeight={height}
/>
<NavBar />
<div class="Container" bind:this={container} />
<!--<svelte:window bind:innerWidth bind:innerHeight /> -->
<style>
#container {
.Container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>

View File

@ -0,0 +1,24 @@
<script context="module">
import 'aframe';
import '@ar-js-org/ar.js/aframe/build/aframe-ar';
</script>
<!--
<script>
let Angle = 45;
setInterval(() => {
Angle++;
}, 100);
</script>
-->
<a-scene embedded arjs>
<a-marker preset="hiro">
<a-entity
position="0 0 0"
scale="0.10 0.10 0.10"
gltf-model="/models/dingus_the_cat.glb"
/>
</a-marker>
<a-entity camera />
</a-scene>

View File

@ -0,0 +1,45 @@
<script lang="ts">
import { onMount } from 'svelte';
import CameraPreview from './CameraPreview.svelte';
import { getMediaStream, getImageCapture } from '../helpers/mediaHelper';
export let width: number;
export let height: number;
let container: HTMLElement;
let cameraWidth: number = 0;
let cameraHeight: number = 0;
let pictureUrl: string;
let imageCapture: ImageCapture;
let mediaStreamPromise: Promise<MediaStream>;
onMount(() => {
mediaStreamPromise = getMediaStream({ video: true }).then((mediaStream) => {
imageCapture = getImageCapture(mediaStream);
return mediaStream;
});
});
</script>
<div class="Container">
{#await mediaStreamPromise}
<h1>Waiting for camera....</h1>
{:then mediaStream}
<CameraPreview {mediaStream} {height} {width} />
{:catch error}
<h1>Error: {error.message}</h1>
{/await}
</div>
<style>
.Container {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
</style>

View File

@ -0,0 +1,24 @@
<script lang="ts">
export let mediaStream: MediaStream;
export let width: number;
export let height: number;
function srcObject(node, stream) {
node.srcObject = stream;
return {
update(newStream) {
if (node.srcObject != newStream) {
node.srcObject = newStream;
}
},
};
}
</script>
<video
use:srcObject={mediaStream}
width={width}
height={height}
autoplay
playsinline
/>

View File

@ -4,18 +4,15 @@ enum Methods {
'PUT' = 'PUT',
}
export async function get<T>(route: string): Promise<T | null> {
export async function get<T>(route: string): Promise<T> {
return request<T>('GET', route);
}
export async function post<T>(
route: string,
data?: unknown,
): Promise<T | null> {
export async function post<T>(route: string, data?: unknown): Promise<T> {
return request<T>('POST', route, data);
}
export async function put<T>(route: string, data: unknown): Promise<T | null> {
export async function put<T>(route: string, data: unknown): Promise<T> {
return request<T>('PUT', route, data);
}
@ -23,7 +20,7 @@ async function request<T>(
method: keyof typeof Methods,
route: string,
data?: unknown,
): Promise<T | null> {
): Promise<T> {
const response = await fetch(`${process.env.APIURL}${route}`, {
headers: {
'content-type': 'application/json',
@ -34,8 +31,11 @@ async function request<T>(
body: data ? JSON.stringify(data) : null,
});
if (!response.ok) throw new Error(await response.json());
if (response.ok && response.status !== 204) {
return response.json() as T;
}
return null;
return {} as T;
}

View File

@ -1,22 +1,18 @@
import type { CreateUserBody, LoginUserBody, UserInfo } from '@core';
import { post, get } from './request';
import { currentUser } from '../store/user';
export async function login(raw: LoginUserBody) {
const user = await post<UserInfo>('/user/login', raw);
currentUser.set(user);
return user;
return post<UserInfo>('/user/login', raw);
}
export async function logout() {
await post('/user/logout');
currentUser.set(null);
await post<void>('/user/logout');
}
export async function read(uuid: string) {
const user = await get<UserInfo>(`/user/read/${uuid}`);
return get<UserInfo>(`/user/read/${uuid}`);
}
export async function create(raw: CreateUserBody) {
const user = await post<UserInfo>('/user/create', raw);
return post<UserInfo>('/user/create', raw);
}

View File

@ -0,0 +1,10 @@
function getMediaStream(constraints = { video: true }) {
return navigator.mediaDevices.getUserMedia(constraints);
}
function getImageCapture(mediaStream) {
const track = mediaStream.getVideoTracks()[0];
return new ImageCapture(track);
}
export { getMediaStream, getImageCapture };

View File

@ -3,6 +3,7 @@
import NavBar from '../components/NavBar.svelte';
import { Form, Input, Button } from 'spaper';
import { login } from '../functions/user';
import { currentUser } from '../store/user';
import { useNavigate } from 'svelte-navigator';
const user: LoginUserBody = {
@ -13,10 +14,11 @@
const navigate = useNavigate();
const loginHandler = async () => {
const result = await login(user);
if (result) {
try {
const res = await login(user);
currentUser.set(res);
navigate('/');
}
} catch (error) {}
};
</script>
@ -39,7 +41,7 @@
type="secondary"
class="row sm-2 col-4"
block
on:click={() => loginHandler()}>Sign in</Button
on:click={loginHandler}>Sign in</Button
>
</Form>
</div>

View File

@ -8,12 +8,16 @@
const navigate = useNavigate();
const logoutHandler = async () => {
await logout();
navigate('/');
try {
await logout();
} finally {
currentUser.set(null);
navigate('/');
}
};
</script>
<Button type="danger" block on:click={() => logoutHandler()}>Logout</Button>
<Button type="danger" block on:click={logoutHandler}>Logout</Button>
{$currentUser?.uuid}
{$currentUser?.username}
{$currentUser?.role}

View File

@ -0,0 +1,26 @@
<script lang="ts">
import ARHandler from '../components/ARHandler.svelte';
import NavBar from '../components/NavBar.svelte';
let containerHeight: number;
let containerWidth: number;
</script>
<div
class="viewAR"
bind:clientHeight={containerHeight}
bind:clientWidth={containerWidth}
>
<ARHandler/>
<!-- <Camera height={containerHeight} width={containerWidth} /> -->
<!-- <View3D height={containerHeight} width={containerWidth} /> -->
</div>
<NavBar />
<style>
.viewAR {
position: absolute;
height: 100%;
width: 100%;
}
</style>

View File

@ -5,7 +5,8 @@
"baseUrl": "./src",
"paths": {
"@core": ["../../core/src"]
}
},
"allowJs": true
},
"include": ["src/**/*"],
"exclude": ["node_modules/*", "public/*"]