Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Small fixes #236

Merged
merged 7 commits into from
May 6, 2024
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
8 changes: 7 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,15 @@ jobs:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
env:
JWT_KEY: ${{ secrets.JWT_KEY }}
with:
name: arquisoft/wiq_en3b/authservice
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: users/authservice
buildargs: JWT_KEY

docker-push-userservice:
name: Push user service Docker Image to GitHub Packages
Expand All @@ -101,12 +104,15 @@ jobs:
- uses: actions/checkout@v4
- name: Publish to Registry
uses: elgohr/Publish-Docker-Github-Action@v5
env:
JWT_KEY: ${{ secrets.JWT_KEY }}
with:
name: arquisoft/wiq_en3b/userservice
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
registry: ghcr.io
workdir: users/userservice
buildargs: JWT_KEY

docker-push-questionservice:
name: Push question service Docker Image to GitHub Packages
Expand Down Expand Up @@ -178,8 +184,8 @@ jobs:
cp -r ./wiq_en3b/gatewayservice/ .
echo -e "${{ secrets.CERTIFICATE }}" > gatewayservice/certificate/certificate.crt
echo -e "${{ secrets.CERTIFICATE_KEY }}" > gatewayservice/certificate/certificatekey.key
echo -e "\n[security]\nadmin_user=${{ secrets.GRAFANA_USER }}\nadmin_password=${{ secrets.GRAFANA_PASSWORD }}" >> gatewayservice/monitoring/grafana/grafana.ini
wget https://raw.githubusercontent.com/arquisoft/wiq_en3b/master/docker-compose.yml -O docker-compose.yml
wget https://raw.githubusercontent.com/arquisoft/wiq_en3b/master/.env
docker compose --profile prod down
docker compose --profile prod up -d --pull always
docker exec grafana-wiq_en3b grafana-cli admin reset-admin-password ${{ secrets.GRAFANA_PASSWORD }}
18 changes: 9 additions & 9 deletions docs/src/01_introduction_and_goals.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -95,23 +95,23 @@ A table with quality goals and concrete scenarios, ordered by priorities
| Consider incorporating user feedback and usability testing to refine the user interface.

| 2
| Availability
| The application must be accessible 24 hours a day. While complete availability may be impossible over extended periods, minimizing downtime and making interruptions imperceptible to users is key.
| Implementing redundancy and failover mechanisms can help ensure continuous availability.

| 3
| Accessibility
| Any user must be able to enjoy playing with our application despite any disability they could have.
| Any user must be able to enjoy playing with our application despite any disability they could have.
| HTML standards must be followed to try to minimize the lack of Accessibility of our Application. Another important feature is the contrast of our web. All of these can be tested with Accessibility tools available on Internet.

| 3
| Performance
| The software should have acceptable response time to provide a smooth user experience. | Basic optimization techniques can improve performance.

| 4
| Security
| The application should stick to industry best practices for security to protect against unauthorized access, data breaches, and other threats.
| The application should stick to industry best practices for security to protect against unauthorized access, data breaches, and other threats.
| Regular security audits and implementing basic security controls are essential.

| 5
| Performance
| The software should have acceptable response time to provide a smooth user experience. | Basic optimization techniques can improve performance.
| Availability
| Minimizing downtime and making interruptions imperceptible to users is desirable, however, it is difficult to achieve and not a strict requirement. For a game application, continuous availability is not crucial.
| Implementing redundancy and failover mechanisms can enhance availability.

|===

Expand Down
22 changes: 11 additions & 11 deletions docs/src/10_quality_requirements.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -96,28 +96,28 @@ Tabular or free form text.
The application should meet usability standards.
| High

| Adaptability
| If a user accesses the application from a different device than a PC, the application should be able to adapt to the different screen size, providing a satisfactory user experience.
| High

| Performance
| When a user interacts with the system it should react within one second to ensure a smooth and responsive user experience.
| High

| Accessibility
| In case a user with a visual impairment interacts with the web application, it should follow HTML standards to ensure accessibility.
All interactive elements must be navigable using screen readers, text alternatives should be provided for non-text content.
Additionally, the application's color contrast should be enough for people with color blindness.
| High

| Privacy
| If a user provides personal information during the registration, the application should securely handle and store user-provided personal information.
Encryption should be applied for data storage.
| High
| Medium

| Security
| If a malicious user attempts unauthorized access to the application, the application should implement robust authentication mechanisms,
including secure password storage to prevent unauthorized access.
| High

| Adaptability
| If a user accesses the application from a different device than a PC, the application should be able to adapt to the different screen size, providing a satisfactory user experience.
| Medium

| Accessibility
| In case a user with a visual impairment interacts with the web application, it should follow HTML standards to ensure accessibility.
All interactive elements must be navigable using screen readers, text alternatives should be provided for non-text content.
Additionally, the application's color contrast should be enough for people with color blindness.
| Medium

| Availability
Expand Down
33 changes: 33 additions & 0 deletions gatewayservice/test/gateway-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,39 @@ describe('Gateway Service', () => {

expect(response.statusCode).toBe(500);
});

// Test environment variables
it('URI constants should initialize properly to environment variables', async () => {
process.env.WEBAPP_ENDPOINT = 'totallydifferenturi';
process.env.GATEWAY_ENDPOINT = 'totallydifferenturi';

jest.resetModules();
await import('../src/app');
});

// Test environment variable constants
it('constants should initialize properly to environment variables', async () => {

let constants = await import('../src/utils/constants');

let OLD_AUTH_SERVICE_URL = constants.AUTH_SERVICE_URL;
let OLD_USER_SERVICE_URL = constants.USER_SERVICE_URL;
let OLD_HISTORY_SERVICE_URL = constants.HISTORY_SERVICE_URL;
let OLD_QUESTION_SERVICE_URL = constants.QUESTION_SERVICE_URL;

process.env.AUTH_SERVICE_URL = 'totallydifferenturl';
process.env.USER_SERVICE_URL = 'totallydifferenturl';
process.env.HISTORY_SERVICE_URL = 'totallydifferenturl';
process.env.QUESTION_SERVICE_URL = 'totallydifferenturl';
jest.resetModules();
constants = await import('../src/utils/constants');

expect(constants.AUTH_SERVICE_URL).not.toMatch(OLD_AUTH_SERVICE_URL);
expect(constants.USER_SERVICE_URL).not.toMatch(OLD_USER_SERVICE_URL);
expect(constants.HISTORY_SERVICE_URL).not.toMatch(OLD_HISTORY_SERVICE_URL);
expect(constants.QUESTION_SERVICE_URL).not.toMatch(OLD_QUESTION_SERVICE_URL);

});
});

async function testWithoutServices(paramFunc: Function) {
Expand Down
3 changes: 3 additions & 0 deletions users/authservice/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ RUN npm install
# Copy the app source code to the working directory
COPY . .

ARG JWT_KEY='your-secret-key'
ENV JWT_SECRET_KEY=$JWT_KEY

# Expose the port the app runs on
EXPOSE 8002

Expand Down
4 changes: 3 additions & 1 deletion users/authservice/src/controllers/auth-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ const { validateRequiredFields } = require('kaw-users-utils');

import User from '../models/auth-model';

const JWT_SECRET_KEY = process.env.JWT_SECRET_KEY ?? 'your-secret-key';

const loginUser = async (req: Request, res: Response) => {
try {
validateRequiredFields(req, ['username', 'password']);
Expand All @@ -28,7 +30,7 @@ const loginUser = async (req: Request, res: Response) => {
// Check if the user exists and verify the password
if (user && (await bcrypt.compare(password, user.password))) {
// Generate a JWT token
const token = jwt.sign({ userId: user._id }, 'your-secret-key', {
const token = jwt.sign({ userId: user._id }, JWT_SECRET_KEY, {
expiresIn: '1h',
});
// Respond with the token and user information
Expand Down
6 changes: 6 additions & 0 deletions users/authservice/test/auth-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,12 @@ describe('Auth Service', () => {
});
expect(response.status).toBe(500);
});
// JWT token
it('JWT token should be properly initialized', async () => {
process.env.JWT_SECRET_KEY = 'just_a_different_key'
jest.resetModules();
await import('../src/controllers/auth-controller');
});
});

async function testWithoutDatabase(paramFunc : Function) {
Expand Down
3 changes: 3 additions & 0 deletions users/userservice/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ RUN npm install
# Copy the app source code to the working directory
COPY . .

ARG JWT_KEY='your-secret-key'
ENV JWT_SECRET_KEY=$JWT_KEY

# Expose the port the app runs on
EXPOSE 8001

Expand Down
4 changes: 3 additions & 1 deletion users/userservice/src/utils/async-verification.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import jwt from 'jsonwebtoken';

const JWT_SECRET_KEY = process.env.JWT_SECRET_KEY ?? 'your-secret-key';

const verifyJWT = async (token: string) => {
return new Promise((resolve, reject) => {
jwt.verify(token, 'your-secret-key', (err, decoded) => {
jwt.verify(token, JWT_SECRET_KEY, (err, decoded) => {
if (err) {
reject(err);
} else {
Expand Down
18 changes: 16 additions & 2 deletions users/userservice/test/user-service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Request, Response } from 'express';
import { verifyJWT } from "../src/utils/async-verification";

let mongoServer: MongoMemoryServer;
const JWT_SECRET_KEY = 'your-secret-key';

beforeAll(async () => {
mongoServer = await MongoMemoryServer.create();
Expand Down Expand Up @@ -122,7 +123,7 @@ describe('User Service', () => {
const user = await User.findOne({ username:'testuser' });

// Generates a temporary token for this and other tests
testToken = jwt.sign({ userId: user!._id }, 'your-secret-key', {
testToken = jwt.sign({ userId: user!._id }, JWT_SECRET_KEY, {
expiresIn: '2m',
});

Expand Down Expand Up @@ -237,7 +238,7 @@ describe('User Service', () => {
};
const newUser = await User.findOne({ username:'highestscoreuser' });
// Generates a temporary token for this test
const testToken2 = jwt.sign({ userId: newUser!._id }, 'your-secret-key', {
const testToken2 = jwt.sign({ userId: newUser!._id }, JWT_SECRET_KEY, {
expiresIn: '2m',
});

Expand Down Expand Up @@ -571,6 +572,19 @@ describe('User Service', () => {

expect(() => validateProfileBody(mockRequest, user[0])).toThrow();
});

// JWT token
it('JWT token should be properly initialized', async () => {
jest.resetModules();
let verification = await import('../src/utils/async-verification');
let isTokenValid = await verification.verifyJWT(testToken);
expect(isTokenValid).not.toBeUndefined();

process.env.JWT_SECRET_KEY = 'just_a_different_key'
jest.resetModules();
verification = await import('../src/utils/async-verification');
await expect(verification.verifyJWT(testToken)).rejects.toThrow();
});
});

async function testWithoutDatabase(paramFunc : Function) {
Expand Down
2 changes: 1 addition & 1 deletion webapp/public/assets/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"play_again": "Play Again",
"go_back_button": "Go Back",
"xshare_button": "Share your results",
"tweetShare": "---- 🤔 Know and Win 🤔 ----%0A%0AI have correctly answered {{correct}}/{{total}} questions and earned {{points}} points 💪💪%0ACome and play this incredible trivia game and try to beat me!! 😎%0A"
"tweetShare": "---- 🤔 Know and Win 🤔 ----%0A%0AI have correctly answered {{xresult}} questions and earned {{points}} points 💪💪%0ACome and play this incredible trivia game and try to beat me!! 😎%0A"
}
},
"home": {
Expand Down
2 changes: 1 addition & 1 deletion webapp/public/assets/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@
"play_again": "Jugar de nuevo",
"go_back_button": "Volver",
"xshare_button": "Comparte tu resultado",
"tweetShare": "---- 🤔 Saber y Ganar 🤔 ----%0A%0AHe respondido correctamente {{correct}}/{{total}} preguntas y he ganado {{points}} puntos 💪💪%0AVen y juega este increíble juego de preguntas e intenta vencerme!!😎%0A"
"tweetShare": "---- 🤔 Saber y Ganar 🤔 ----%0A%0AHe respondido correctamente {{xresult}} preguntas y he ganado {{points}} puntos 💪💪%0AVen y juega este increíble juego de preguntas e intenta vencerme!!😎%0A"
}
},
"home": {
Expand Down
2 changes: 1 addition & 1 deletion webapp/public/assets/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"play_again": "Rejouer",
"go_back_button": "Retour",
"xshare_button": "Partagez vos résultats",
"tweetShare": "---- 🤔 Know and Win 🤔 ----%0A%0AJ'ai répondu correctement à {{correct}}/{{total}} questions et j'ai gagné {{points}} points 💪💪%0AViens jouer à ça jeu-questionnaire incroyable et essayez de me battre!! 😎%0A"
"tweetShare": "---- 🤔 Know and Win 🤔 ----%0A%0AJ'ai répondu correctement à {{xresult}} questions et j'ai gagné {{points}} points 💪💪%0AViens jouer à ça jeu-questionnaire incroyable et essayez de me battre!! 😎%0A"
}
},
"home": {
Expand Down
2 changes: 1 addition & 1 deletion webapp/public/assets/locales/uk/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"play_again": "Грати знову",
"go_back_button": "Повернутися",
"xshare_button": "Поділіться своїми результатами",
"tweetShare": "---- 🤔 Знай і перемагай 🤔 ----%0A%0A Я правильно відповів на {{correct}}/{{total}} запитань і заробив {{points}} балів 💪💪%0A Приходь і грай у це неймовірна дрібниця і спробуй мене перемогти 😎%0A"
"tweetShare": "---- 🤔 Знай і перемагай 🤔 ----%0A%0A Я правильно відповів на {{xresult}} запитань і заробив {{points}} балів 💪💪%0A Приходь і грай у це неймовірна дрібниця і спробуй мене перемогти 😎%0A"
}
},
"home": {
Expand Down
7 changes: 4 additions & 3 deletions webapp/src/components/FinalResult/FinalResult.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ const FinalResult = ({ result, quizLength, points, onPlayAgain, goBack }) => {
const { t } = useTranslation()

const tweetUrl = "https://twitter.com/intent/tweet"

// https://developer.twitter.com/en/docs/twitter-for-websites/tweet-button/overview
let tweetToShare = tweetUrl + "?text=" + t("play.result.tweetShare",{correct: result, total: quizLength, points: points})
let tweetToShare = tweetUrl + "?text=" + t("play.result.tweetShare",{xresult: quizLength === 0 ? result : result + "%2F" + quizLength, points: points})
tweetToShare += "&url=https://www.kawgame.xyz%0A"
tweetToShare += "&hashtags=kaw,wikidata,know,win,game"

Expand All @@ -24,7 +24,8 @@ const FinalResult = ({ result, quizLength, points, onPlayAgain, goBack }) => {
</p>
<p>{t('play.result.points', { points: points })}</p>
<Button onClick={onPlayAgain}>{t('play.result.play_again')}</Button>
<XButton href={tweetToShare} textShare={t('play.result.xshare_button')}></XButton>
<XButton href={tweetToShare} textShare={t('play.result.xshare_button')}>
</XButton>
<Button onClick={goBack} className="danger">
{t('play.result.go_back_button')}
</Button>
Expand Down