Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions apps/web/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,24 +23,30 @@ ENV FORCE_COLOR=1

RUN npx turbo build --filter=web... --output-logs=new-only --summarize

FROM nginx AS runner
FROM nginx:1.21.6-alpine AS runner

# Non-root user
USER 1001

ENV PORT 80
ENV ROOT_PATH /var/www
ENV LOG_PATH /var/log/cloudforet
ENV NGINX_CONF_PATH /etc/nginx/conf.d

RUN mkdir -p ${LOG_PATH}/nginx
RUN mkdir -p ${LOG_PATH}/nginx && \
chown -R 1001:1001 ${LOG_PATH}

RUN rm /etc/nginx/conf.d/default.conf
COPY apps/web/pkg/proxy.conf ${NGINX_CONF_PATH}/proxy.conf

# forward request and error logs to docker log collector
RUN ln -sf /dev/stdout /var/log/nginx/spaceone-access.log \
&& ln -sf /dev/stderr /var/log/nginx/spaceone-error.log
RUN ln -sf /dev/stdout ${LOG_PATH}/nginx/spaceone-access.log \
&& ln -sf /dev/stderr ${LOG_PATH}/nginx/spaceone-error.log

COPY --from=installer /app/apps/web/dist/. ${ROOT_PATH}/

RUN chown -R 1001:1001 ${ROOT_PATH} ${NGINX_CONF_PATH}

# Enable only for turbo debugging purposes
#RUN mkdir -p ${LOG_PATH}/turbo
#COPY --from=installer /app/.turbo/runs/. ${LOG_PATH}/turbo
Expand Down
2 changes: 1 addition & 1 deletion apps/web/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ export default defineConfig({

/* Configure projects for major browsers */
projects: [
{ name: 'setup', testMatch: /.*\.setup\.ts/ },
{ name: 'setup', testMatch: /^[\w-.]+\.setup\.ts$/ },
{
name: 'chromium',
use: {
Expand Down
52 changes: 35 additions & 17 deletions apps/web/public/lottie.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
(typeof navigator !== "undefined") && (function(root, factory) {
if (typeof define === "function" && define.amd) {
define(function() {
return factory(root);
});
} else if (typeof module === "object" && module.exports) {
module.exports = factory(root);
} else {
root.lottie = factory(root);
root.bodymovin = root.lottie;
}
}((window || {}), function(window) {
(typeof navigator !== "undefined") && (function(root, factory) {
if (typeof define === "function" && define.amd) {
define(function() {
return factory(root);
});
} else if (typeof module === "object" && module.exports) {
module.exports = factory(root);
} else {
root.lottie = factory(root);
root.bodymovin = root.lottie;
}
}((window || {}), function(window) {
/* global locationHref:writable, animationManager, subframeEnabled:writable, defaultCurveSegments:writable, roundValues,
expressionsPlugin:writable, PropertyFactory, ShapePropertyFactory, Matrix */
/* exported locationHref, subframeEnabled, expressionsPlugin */
Expand Down Expand Up @@ -5987,7 +5987,8 @@ TextProperty.prototype.completeTextData = function (documentData) {
letterData = letters[i];
if (currentInd != letterData.anIndexes[j]) { // eslint-disable-line eqeqeq
currentInd = letterData.anIndexes[j];
newInd = indexes.splice(Math.floor(Math.random() * indexes.length), 1)[0];
var randomValue = window.crypto.getRandomValues(new Uint32Array(1))[0] / (0xffffffff + 1);
newInd = indexes.splice(Math.floor(randomValue * indexes.length), 1)[0];
}
letterData.anIndexes[j] = newInd;
}
Expand Down Expand Up @@ -13576,7 +13577,24 @@ var ExpressionManager = (function () {
var velocityAtTime;

var scoped_bm_rt;
var expression_function = eval('[function _expression_function(){' + val + ';scoped_bm_rt=$bm_rt}]')[0]; // eslint-disable-line no-eval
var expression_function;
try {
if (!/^[0-9+\-*/\s;]+$/.test(val)) {
throw new Error('Invalid characters in function definition');
}

expression_function = new Function(`
return function _expression_function(){
${val};
scoped_bm_rt = $bm_rt;
};
`)();

expression_function();
} catch (error) {
console.error('Error creating function:', error);
expression_function = null;
}
var numKeys = property.kf ? data.k.length : 0;

var active = !this.data || this.data.hd !== true;
Expand Down Expand Up @@ -15936,6 +15954,6 @@ if (standalone) {
renderer = getQueryVariable('renderer');
}
var readyStateCheckInterval = setInterval(checkReady, 100);

return lottie;
}));
return lottie;
}));
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// such as <p></p>
export const emptyHtmlRegExp = /<[^/>][^>]*><\/[^>]+>/;
export const emptyHtmlRegExp = /<([a-zA-Z0-9]+)[^>]*?><\/\1>/;
6 changes: 4 additions & 2 deletions apps/web/src/common/modules/project/ProjectSelectDropdown.vue
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import type { ProjectGroupReferenceMap } from '@/store/reference/project-group-r
import type { ProjectReferenceMap } from '@/store/reference/project-reference-store';
import type { ReferenceMap } from '@/store/reference/type';

import getRandomId from '@/lib/random-id-generator';

import ErrorHandler from '@/common/composables/error/errorHandler';

import { indigo, peacock } from '@/styles/colors';
Expand Down Expand Up @@ -109,7 +111,7 @@ const state = reactive({
if (props.multiSelectable) return PCheckbox;
return PRadio;
}),
contextKey: Math.floor(Math.random() * Date.now()),
contextKey: getRandomId(),
});
const projectTreeHelper = useProjectTree();

Expand Down Expand Up @@ -246,7 +248,7 @@ const handleUpdateVisibleMenu = (value: boolean) => {

const refreshProjectTree = async () => {
await allReferenceStore.load('project', { force: true });
state.contextKey = Math.floor(Math.random() * Date.now());
state.contextKey = getRandomId();
};

const handleClickCreateButton = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const getMockSubData = (length = 10, year = 2023): SubData[] => {
return range(length).map(() => {
const refinedMonth = month < 10 ? `0${month}` : month;
month += 1;
return { date: `${year}-${refinedMonth}`, value: Math.random() * 100 };
const randomValue = window.crypto.getRandomValues(new Uint32Array(1))[0] / 0xffffffff * 100;
return { date: `${year}-${refinedMonth}`, value: randomValue };
});
};
interface MockData {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,36 @@ import type { PublicDataTableModel } from '@/schema/dashboard/public-data-table/

import type { DataTableOptions } from '@/common/modules/widgets/types/widget-model';

export const getDuplicatedDataTableName = (name: string, dataTables: Partial<PublicDataTableModel | PrivateDataTableModel>[]): string => {
export const getDuplicatedDataTableName = (
name: string,
dataTables: Partial<PublicDataTableModel | PrivateDataTableModel>[],
): string => {
let _name = name;
const _regex = /^(.*?)\s*\((\d+)\)$/i;
const dataTableNames = dataTables.map((dataTable) => dataTable.name);

while (dataTableNames.includes(_name)) {
const match = _regex.exec(_name);
if (match) {
const baseName = match[1];
const numberStr = match[2];
const newNumber = numberStr ? parseInt(numberStr) + 1 : 2;
_name = `${baseName} (${newNumber})`;
const lastOpenParenIndex = _name.lastIndexOf('(');
const lastCloseParenIndex = _name.lastIndexOf(')');

if (
lastOpenParenIndex !== -1
&& lastCloseParenIndex === _name.length - 1
&& lastOpenParenIndex < lastCloseParenIndex
) {
const baseName = _name.slice(0, lastOpenParenIndex).trim();
const numberStr = _name.slice(lastOpenParenIndex + 1, lastCloseParenIndex);
const number = parseInt(numberStr);

if (!Number.isNaN(number)) {
_name = `${baseName} (${number + 1})`;
} else {
_name = `${_name} (2)`;
}
} else {
_name = `${_name} (2)`;
}
}

return _name;
};

Expand Down
4 changes: 3 additions & 1 deletion apps/web/src/lib/random-id-generator.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { v4 as uuidv4 } from 'uuid';

const getRandomId = ():string => {
try {
if (window) return (window.crypto.getRandomValues(new Uint32Array(1))[0]).toString();
throw new Error('No window object found');
} catch (e) {
console.error(e);
return (Math.random()).toString();
return uuidv4();
}
};

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface UpdatePasswordParameters {
new_password: string;
current_password?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,22 @@ const openNameFormModal = (modalType: string) => {
};
const getDuplicatedMetricName = (name: string): string => {
let _name = name;
const _regex = /^(.*?)\s*copy(\s+(\d+))?$/i;

while (state.existingMetricNameList.includes(_name)) {
const match = _regex.exec(_name);
if (match) {
const baseName = match[1];
const numberStr = match[3];
const newNumber = numberStr ? parseInt(numberStr) + 1 : 2;
_name = `${baseName} copy ${newNumber}`;
const trimmedName = _name.trim();

if (trimmedName.endsWith(' copy')) {
_name = `${trimmedName} 2`;
} else if (trimmedName.match(/ copy \d+$/)) {
const lastSpaceIndex = trimmedName.lastIndexOf(' ');
const baseName = trimmedName.slice(0, lastSpaceIndex);
const number = parseInt(trimmedName.slice(lastSpaceIndex + 1));
_name = `${baseName} ${number + 1}`;
} else {
_name = `${_name} copy`;
}
}

return _name;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ const signIn = async () => {
},
});
} else {
displayStore.setSignInFailedMessage(e.message);
ErrorHandler.handleError(e);
displayStore.setIsSignInFailed(true);
}
Expand Down Expand Up @@ -142,6 +143,7 @@ const handleClickResetPassword = async () => {
appearance-type="masking"
:invalid="invalid"
block
skip-mask-toggle-tab-index
@update:value="checkPassword"
@keydown.prevent.enter="signIn"
/>
Expand Down
17 changes: 14 additions & 3 deletions apps/web/src/services/auth/components/SignInRightContainer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<div v-if="showErrorMessage"
class="error-msg-box"
>
<span class="error-msg">{{ $t('COMMON.SIGN_IN.ALT_E_SIGN_IN') }}</span>
<span class="error-msg">{{ errorMessage }}</span>
<p-i name="ic_close"
width="1.5rem"
height="1.5rem"
Expand All @@ -39,6 +39,8 @@ import {
PI, screens,
} from '@cloudforet/mirinae';

import { i18n } from '@/translations';

import { useDisplayStore } from '@/store/display/display-store';
import { useDomainStore } from '@/store/domain/domain-store';

Expand Down Expand Up @@ -67,6 +69,15 @@ export default {
const state = reactive({
symbolImage: computed<string|undefined>(() => domainStore.getters.domainSymbolImage),
isMobileSize: computed<boolean>(() => width.value < screens.mobile.max),
errorMessage: computed<string>(() => {
const signInBlockMessage = i18n.t('COMMON.SIGN_IN.SIGN_IN_BLOCK_MESSAGE');
const basicMessage = i18n.t('COMMON.SIGN_IN.ALT_E_SIGN_IN');
const signInAPIErrorMessage = displayStore.state.signInFailedMessage;
if (signInAPIErrorMessage.includes('Login is blocked')) {
return signInBlockMessage;
}
return basicMessage;
}),
});

/* event */
Expand Down Expand Up @@ -125,9 +136,9 @@ export default {
display: flex;
justify-content: space-between;
right: 0;
bottom: 0;
top: -0.5rem;
left: 0;
height: 2.25rem;
min-height: 2.25rem;
padding: 0.5rem;

.error-msg {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ const getMockSubData = (length = 10, year = 2023): SubData[] => {
return range(length).map(() => {
const refinedMonth = month < 10 ? `0${month}` : month;
month += 1;
return { date: `${year}-${refinedMonth}`, value: Math.random() * 100 };
const randomValue = window.crypto.getRandomValues(new Uint32Array(1))[0] / 0xffffffff * 100;
return { date: `${year}-${refinedMonth}`, value: randomValue };
});
};
interface MockData {
Expand Down
16 changes: 15 additions & 1 deletion apps/web/src/services/iam/helpers/generate-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,22 @@ export const generatePassword = () => {
let randomPassword = '';

do {
randomPassword = Array.from({ length: 12 }, () => allCharacters[Math.floor(Math.random() * allCharacters.length)]).join('');
randomPassword = Array.from({ length: 12 }, () => {
const randomIndex = getSecureRandomIndex(allCharacters.length);
return allCharacters[randomIndex];
}).join('');
} while (!regex.test(randomPassword));

return randomPassword;
};

const getSecureRandomIndex = (max: number) => {
const maxAllowedValue = Math.floor(0xffffffff / max) * max;
let randomValue;

do {
randomValue = window.crypto.getRandomValues(new Uint32Array(1))[0];
} while (randomValue >= maxAllowedValue);

return randomValue % max;
};
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,21 @@ export const checkEmailFormat = (userID: string) => {
isValid: true,
invalidText: '' as TranslateResult,
};
const emailCheckRegex = /\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/;

// RFC 5321
if (userID.length > 320) {
validation.isValid = false;
validation.invalidText = i18n.t('IAM.USER.FORM.EMAIL_INVALID');
return validation;
}

const emailCheckRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
if (!emailCheckRegex.test(userID)) {
validation.isValid = false;
validation.invalidText = i18n.t('IAM.USER.FORM.EMAIL_INVALID');
}
return validation;
};

export const checkEmptyValue = async (valueForCheck: string) => {
const validation = {
isValid: true,
Expand Down
Loading