reworked user.ts

- fixed imports
- removed complicated ternary operators
- simplified parseProfile
- added enum ProviderEnum
- added type Profile
- added type PhotoProfile

Signed-off-by: Philip Molares <philip.molares@udo.edu>
Signed-off-by: David Mehren <dmehren1@gmail.com>
This commit is contained in:
Philip Molares 2020-04-11 14:12:39 +02:00 committed by David Mehren
parent 2c40255ac2
commit 4eb71d6cad
No known key found for this signature in database
GPG key ID: 6017AF117F9756CB

View file

@ -1,17 +1,45 @@
import { Note } from './note'; import { Note } from './note'
import { Table, BeforeCreate, BeforeUpdate, HasMany, Unique, IsUUID, IsEmail, Column, DataType, PrimaryKey, Model, Default } from 'sequelize-typescript'; import { Table, BeforeCreate, BeforeUpdate, HasMany, Unique, IsEmail, Column, DataType, PrimaryKey, Model, Default } from 'sequelize-typescript'
import scrypt from 'scrypt-kdf'; import scrypt from 'scrypt-kdf'
import { generateAvatarURL } from '../letter-avatars'; import { generateAvatarURL } from '../letter-avatars'
import logger from '../logger'; import logger from '../logger'
import { UUIDV4 } from 'sequelize'
var Sequelize = require('sequelize')
// core // core
export enum ProviderEnum {
facebook = 'facebook',
twitter = 'twitter',
github = 'github',
gitlab = 'gitlab',
dropbox = 'dropbox',
google = 'google',
ldap = 'ldap',
saml = 'saml',
}
// ToDo Fix this 'any' mess
export type Profile = {
id: string;
username: string;
displayName: string;
emails: any[];
avatarUrl: string;
profileUrl: string;
provider: ProviderEnum;
photos: any[];
}
export type PhotoProfile = {
name: string;
photo: string;
biggerphoto: string;
}
@Table @Table
export class User extends Model<User> { export class User extends Model<User> {
@PrimaryKey @PrimaryKey
@Default(Sequelize.UUIDV4) @Default(UUIDV4)
@Column(DataType.UUID) @Column(DataType.UUID)
id: string; id: string;
@ -23,7 +51,7 @@ export class User extends Model<User> {
profile: string; profile: string;
@Column(DataType.TEXT) @Column(DataType.TEXT)
histroy: string; history: string;
@Column(DataType.TEXT) @Column(DataType.TEXT)
accessToken: string; accessToken: string;
@ -41,52 +69,67 @@ export class User extends Model<User> {
@Column(DataType.TEXT) @Column(DataType.TEXT)
password: string; password: string;
verifyPassword(attempt: string) { verifyPassword (attempt: string): Promise<boolean> {
return scrypt.verify(Buffer.from(this.password, 'hex'), attempt); return scrypt.verify(Buffer.from(this.password, 'hex'), attempt)
} }
@HasMany(() => Note, { foreignKey: 'lastchangeuserId', constraints: false }) @HasMany(() => Note, { foreignKey: 'lastchangeuserId', constraints: false })
@HasMany(() => Note, { foreignKey: 'ownerId', constraints: false }) @HasMany(() => Note, { foreignKey: 'ownerId', constraints: false })
static parsePhotoByProfile(profile: any, bigger: boolean) { static parsePhotoByProfile (profile: Profile, bigger: boolean): string {
let photo: string; let photo: string
switch (profile.provider) { switch (profile.provider) {
case 'facebook': case ProviderEnum.facebook:
photo = 'https://graph.facebook.com/' + profile.id + '/picture' photo = 'https://graph.facebook.com/' + profile.id + '/picture'
if (bigger) photo += '?width=400' if (bigger) {
else photo += '?width=96' photo += '?width=400'
} else {
photo += '?width=96'
}
break break
case 'twitter': case ProviderEnum.twitter:
photo = 'https://twitter.com/' + profile.username + '/profile_image' photo = 'https://twitter.com/' + profile.username + '/profile_image'
if (bigger) photo += '?size=original' if (bigger) {
else photo += '?size=bigger' photo += '?size=original'
} else {
photo += '?size=bigger'
}
break break
case 'github': case ProviderEnum.github:
photo = 'https://avatars.githubusercontent.com/u/' + profile.id photo = 'https://avatars.githubusercontent.com/u/' + profile.id
if (bigger) photo += '?s=400' if (bigger) {
else photo += '?s=96' photo += '?s=400'
} else {
photo += '?s=96'
}
break break
case 'gitlab': case ProviderEnum.gitlab:
photo = profile.avatarUrl photo = profile.avatarUrl
if (photo) { if (photo) {
if (bigger) photo = photo.replace(/(\?s=)\d*$/i, '$1400') if (bigger) {
else photo = photo.replace(/(\?s=)\d*$/i, '$196') photo = photo.replace(/(\?s=)\d*$/i, '$1400')
} else {
photo = photo.replace(/(\?s=)\d*$/i, '$196')
}
} else { } else {
photo = generateAvatarURL(profile.username) photo = generateAvatarURL(profile.username)
} }
break break
case 'dropbox': case ProviderEnum.dropbox:
photo = generateAvatarURL('', profile.emails[0].value, bigger) photo = generateAvatarURL('', profile.emails[0].value, bigger)
break break
case 'google': case ProviderEnum.google:
photo = profile.photos[0].value photo = profile.photos[0].value
if (bigger) photo = photo.replace(/(\?sz=)\d*$/i, '$1400') if (bigger) {
else photo = photo.replace(/(\?sz=)\d*$/i, '$196') photo = photo.replace(/(\?sz=)\d*$/i, '$1400')
} else {
photo = photo.replace(/(\?sz=)\d*$/i, '$196')
}
break break
case 'ldap': case ProviderEnum.ldap:
photo = generateAvatarURL(profile.username, profile.emails[0], bigger) photo = generateAvatarURL(profile.username, profile.emails[0], bigger)
break break
case 'saml': case ProviderEnum.saml:
photo = generateAvatarURL(profile.username, profile.emails[0], bigger) photo = generateAvatarURL(profile.username, profile.emails[0], bigger)
break break
default: default:
@ -95,7 +138,8 @@ export class User extends Model<User> {
} }
return photo return photo
} }
static parseProfileByEmail(email: string) {
static parseProfileByEmail (email: string): PhotoProfile {
return { return {
name: email.substring(0, email.lastIndexOf('@')), name: email.substring(0, email.lastIndexOf('@')),
photo: generateAvatarURL('', email, false), photo: generateAvatarURL('', email, false),
@ -105,41 +149,48 @@ export class User extends Model<User> {
@BeforeUpdate @BeforeUpdate
@BeforeCreate @BeforeCreate
static async updatePasswordHashHook(user: User) { static async updatePasswordHashHook (user: User): Promise<void> {
// suggested way to hash passwords to be able to do this asynchronously: // suggested way to hash passwords to be able to do this asynchronously:
// @see https://github.com/sequelize/sequelize/issues/1821#issuecomment-44265819 // @see https://github.com/sequelize/sequelize/issues/1821#issuecomment-44265819
if (!user.changed('password')) { if (!user.changed('password')) {
return Promise.resolve(); return Promise.resolve()
} }
return scrypt.kdf(user.getDataValue('password'), { logN: 15, r: 8, p: 1 }).then(keyBuf => { return scrypt
user.setDataValue('password', keyBuf.toString('hex')); .kdf(user.getDataValue('password'), { logN: 15, r: 8, p: 1 })
.then(keyBuf => {
user.setDataValue('password', keyBuf.toString('hex'))
}) })
} }
static getProfile(user: User) { static getProfile (user: User): PhotoProfile | null {
if (!user) { if (!user) {
return null return null
} }
return user.profile ? user.parseProfile(user.profile) : (user.email ? User.parseProfileByEmail(user.email) : null)
if (user.profile) {
return user.parseProfile(user.profile)
} else {
if (user.email) {
return User.parseProfileByEmail(user.email)
} else {
return null
}
}
} }
parseProfile(profile: any) { parseProfile (profile: string): PhotoProfile | null {
try { try {
profile = JSON.parse(profile) const parsedProfile: Profile = JSON.parse(profile)
return {
name: parsedProfile.displayName || parsedProfile.username,
photo: User.parsePhotoByProfile(parsedProfile, false),
biggerphoto: User.parsePhotoByProfile(parsedProfile, true)
}
} catch (err) { } catch (err) {
logger.error(err) logger.error(err)
profile = null return null
}
if (profile) {
profile = {
name: profile.displayName || profile.username,
photo: User.parsePhotoByProfile(profile, false),
biggerphoto: User.parsePhotoByProfile(profile, true)
} }
} }
return profile
}
} }