diff --git a/instruction.txt b/instruction.txt new file mode 100644 index 0000000..28357f2 --- /dev/null +++ b/instruction.txt @@ -0,0 +1,21 @@ +- download Aws cli and Aws session manager +- Key generate for KCCB +- port forwarding : + + aws ssm start-session --target i-0c850dcf8b85b1447 --document-name --profile kccb AWS-StartPortForwardingSession --parameters "portNumber"=["8080"],"localPortNumber"=["8080"] + +- run the api in localhost + aws ssm start-session --target i-0c850dcf8b85b1447 --document-name --profile kccb AWS-StartPortForwardingSession --parameters "portNumber"=["5432"],"localPortNumber"=["5431"] + +______________________________________________________________________ + +For database: + - aws ssm start-session --target i-0c850dcf8b85b1447 --profile kccb + - psql -U postgres + - \l + - psql -U kmobile_db_owner -d kmobile_banking + - password : kmobile + - SELECT * FROM users; + - \x + - \d users; -- see the data type of column + - \c kmobile_banking kmobile_app_rw -- alter the user \ No newline at end of file diff --git a/next.config.mjs b/next.config.mjs index 5807599..fa862b7 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -3,7 +3,16 @@ const nextConfig = { experimental: { serverComponentsExternalPackages: ["typeorm", "knex"], }, - reactStrictMode: true + reactStrictMode: true, + // For port transfer + async rewrites() { + return[ + { + source:'/api/:path*', + destination: 'http://localhost:8080/api/:path*', + }, + ]; + }, }; export default nextConfig; diff --git a/src/app/ChangePassword/clientCarousel.tsx b/src/app/ChangePassword/clientCarousel.tsx deleted file mode 100644 index bc19c85..0000000 --- a/src/app/ChangePassword/clientCarousel.tsx +++ /dev/null @@ -1,98 +0,0 @@ -'use client'; - -import { Box, Image, ActionIcon } from '@mantine/core'; -import { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'; -import { useRef } from 'react'; -import DICGC from '@/app/image/DICGC_image.jpg'; -import objective from '@/app/image/objective.jpg'; -import frontPage from '@/app/image/ib_front_page.jpg'; - -export default function CustomCarousel() { - const scrollRef = useRef(null); - const scrollBy = 300; // px per click - - const scrollLeft = () => { - scrollRef.current?.scrollBy({ left: -scrollBy, behavior: 'smooth' }); - }; - - const scrollRight = () => { - scrollRef.current?.scrollBy({ left: scrollBy, behavior: 'smooth' }); - }; - - const images = [DICGC, objective, frontPage]; - - return ( - - {/* Scrollable container */} - - {images.map((img, i) => ( - - {`Slide - - ))} - - - {/* Left Scroll Button */} - - - - - {/* Right Scroll Button */} - - - - - ); -} - \ No newline at end of file diff --git a/src/app/ChangePassword/page.tsx b/src/app/ChangePassword/page.tsx index f12eee3..f4d8bfa 100644 --- a/src/app/ChangePassword/page.tsx +++ b/src/app/ChangePassword/page.tsx @@ -1,55 +1,23 @@ "use client"; import React, { useState, useEffect } from "react"; -import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Stack, Container, rem, Grid } from "@mantine/core"; +import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { Providers } from "@/app/providers"; import { useRouter } from "next/navigation"; import NextImage from "next/image"; import myImage from '@/app/image/ebanking.jpg'; import changePwdImage from '@/app/image/changepw.png'; -import dynamic from 'next/dynamic'; -import RegistrationTimeline from '../_components/timeline/RegistrationTimeline'; -import CaptchaImage from './CaptchaImage'; // adjust path if needed +import CaptchaImage from './CaptchaImage'; - - - - -function generateCaptcha(length = 6) { - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join(""); -} - -export default function Changeloginpwd() { +export default function ChangeLoginPwd() { const router = useRouter(); - // const [error, setError] = useState(null); - //const [CIF, SetCIF] = useState(""); - // const [psw, SetPsw] = useState(""); + const [authorized, SetAuthorized] = useState(null); const [captcha, setCaptcha] = useState(""); - const [inputCaptcha, setInputCaptcha] = useState(""); - const [password, setPassword] = useState(""); const [confirmPassword, setConfirmPassword] = useState(""); - const [error, setError] = useState(""); - - const ClientCarousel = dynamic(() => import('./clientCarousel'), { ssr: false }); - - // const [captcha, setCaptcha] = useState(''); const [captchaInput, setCaptchaInput] = useState(''); const [captchaError, setCaptchaError] = useState(''); - - - - // useEffect(() => { - // setCaptcha(generateCaptcha()); - // }, []); - - // const regenerateCaptcha = () => { - // setCaptcha(generateCaptcha()); - // setInputCaptcha(""); - // }; - useEffect(() => { generateCaptcha(); }, []); @@ -65,158 +33,203 @@ export default function Changeloginpwd() { setCaptchaError(''); }; - return ( - -
- - ebanking - -
+ async function handleSetLoginPassword(e: React.FormEvent) { + e.preventDefault(); + const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/; + if (!password || !confirmPassword) { + notifications.show({ + withBorder: true, + color: "red", + title: "Both password fields are required.", + message: "Both password fields are required.", + autoClose: 5000, + }); + return; + // alert("Both password fields are required."); + } else if (password !== confirmPassword) { + // alert("Passwords do not match."); + notifications.show({ + withBorder: true, + color: "red", + title: "Passwords do not match.", + message: "Passwords do not match.", + autoClose: 5000, + }); + return; + } + else if (!pwdRegex.test(password)) { + // alert("Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long."); + notifications.show({ + withBorder: true, + color: "red", + title: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", + message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", + autoClose: 5000, + }); + return; + } + else if (captchaInput !== captcha) { + setCaptchaError("Incorrect CAPTCHA."); + return; + } + const token = localStorage.getItem("access_token"); + const response = await fetch('api/auth/login_password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify({ + login_password: password, + }), + }); + const data = await response.json(); + if (response.ok) { + // console.log(data); + notifications.show({ + withBorder: true, + color: "green", + title: "Login Password has been set", + message: "Login Password has been set", + autoClose: 5000, + }); + router.push("/ChangeTxn"); + } + else { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later ", + message: "Please try again later ", + autoClose: 5000, + }); + router.push("/login"); + } + } - - Change Password Image - - - Set Login Password + useEffect(() => { + const token = localStorage.getItem("access_token"); + if (!token) { + SetAuthorized(false); + router.push("/login"); + } + else { + SetAuthorized(true); + } + }, []); -
- setPassword(e.currentTarget.value)} - onCopy={(e) => e.preventDefault()} - onPaste={(e) => e.preventDefault()} - onCut={(e) => e.preventDefault()} - /> + if (authorized) { + return ( + +
+ + ebanking + +
- e.preventDefault()} - onPaste={(e) => e.preventDefault()} - onCut={(e) => e.preventDefault()} + + Change Password Image + + + Set Login Password - /> - - {/* CAPTCHA */} -
- -
- - -
- setCaptchaInput(e.currentTarget.value)} + + setPassword(e.currentTarget.value)} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} /> - {captchaError &&

{captchaError}

} -
+ setConfirmPassword(e.currentTarget.value)} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} + /> + {/* CAPTCHA */} +
+ +
+ + +
+ setCaptchaInput(e.currentTarget.value)} + required + /> + {captchaError &&

{captchaError}

} +
- {/* */} + + +

+ { - let pwd = (document.getElementById("loginPassword") as HTMLInputElement).value; - let confirmPwd = (document.getElementById("confirmPassword") as HTMLInputElement).value; - const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/; - if (!pwd || !confirmPwd) { - alert("Both password fields are required."); - } else if (pwd !== confirmPwd) { - alert("Passwords do not match."); - } - else if (!pwdRegex.test(pwd)) { - alert("Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long."); - } - else if (captchaInput !== captcha) { - setCaptchaError("Incorrect CAPTCHA."); - } - - else { - // If all checks pass - localStorage.setItem("password", password); - localStorage.setItem("Tpin_setup", "Y"); - router.push("/ChangeTxn"); - notifications.show({ - title: 'Password Change', - message: 'Login Password has been sucessfully updated', - color: "green", - position: 'bottom-center', - }) - } }} > - Set - - {/* */} - - -

- - - Note: Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. - - -
+ + Note: Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. + +
+ +
- - - - © 2025 KCC Bank. All rights reserved. {" "} + + + © 2025 KCC Bank. All rights reserved. {" "} - - + + +
-
- - ); + + ); + } } diff --git a/src/app/ChangeTxn/clientCarousel.tsx b/src/app/ChangeTxn/clientCarousel.tsx deleted file mode 100644 index bc19c85..0000000 --- a/src/app/ChangeTxn/clientCarousel.tsx +++ /dev/null @@ -1,98 +0,0 @@ -'use client'; - -import { Box, Image, ActionIcon } from '@mantine/core'; -import { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'; -import { useRef } from 'react'; -import DICGC from '@/app/image/DICGC_image.jpg'; -import objective from '@/app/image/objective.jpg'; -import frontPage from '@/app/image/ib_front_page.jpg'; - -export default function CustomCarousel() { - const scrollRef = useRef(null); - const scrollBy = 300; // px per click - - const scrollLeft = () => { - scrollRef.current?.scrollBy({ left: -scrollBy, behavior: 'smooth' }); - }; - - const scrollRight = () => { - scrollRef.current?.scrollBy({ left: scrollBy, behavior: 'smooth' }); - }; - - const images = [DICGC, objective, frontPage]; - - return ( - - {/* Scrollable container */} - - {images.map((img, i) => ( - - {`Slide - - ))} - - - {/* Left Scroll Button */} - - - - - {/* Right Scroll Button */} - - - - - ); -} - \ No newline at end of file diff --git a/src/app/ChangeTxn/page.tsx b/src/app/ChangeTxn/page.tsx index 587def9..37188af 100644 --- a/src/app/ChangeTxn/page.tsx +++ b/src/app/ChangeTxn/page.tsx @@ -1,41 +1,22 @@ "use client"; import React, { useState, useEffect } from "react"; -import { Text, Button, TextInput, PasswordInput, Title, Card, Group, Flex, Box, Image, Anchor, Stack, Container, rem, Grid } from "@mantine/core"; +import { Text, Button, TextInput, PasswordInput, Title, Card, Box, Image } from "@mantine/core"; import { notifications } from "@mantine/notifications"; import { Providers } from "@/app/providers"; import { useRouter } from "next/navigation"; import NextImage from "next/image"; import myImage from '@/app/image/ebanking.jpg'; import changePwdImage from '@/app/image/changepw.png'; -import dynamic from 'next/dynamic'; import CaptchaImage from './CaptchaImage'; -function generateCaptcha(length = 6) { - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join(""); -} - -export default function Changetransactionpwd() { +export default function ChangeTransactionPwd() { const router = useRouter(); - const [error, setError] = useState(null); - const [CIF, SetCIF] = useState(""); - const [psw, SetPsw] = useState(""); + const [authorized, SetAuthorized] = useState(null); + const [password, setPassword] = useState(""); + const [confirmPassword, setConfirmPassword] = useState(""); const [captcha, setCaptcha] = useState(""); - const [inputCaptcha, setInputCaptcha] = useState(""); - const ClientCarousel = dynamic(() => import('./clientCarousel'), { ssr: false }); - //const [captcha, setCaptcha] = useState(''); const [captchaInput, setCaptchaInput] = useState(''); const [captchaError, setCaptchaError] = useState(''); - // const [isClient,SetIsClient] =useState(false); - // useEffect(()=> SetIsClient(true),[]); - // useEffect(() => { - // setCaptcha(generateCaptcha()); - // }, []); - - // const regenerateCaptcha = () => { - // setCaptcha(generateCaptcha()); - // setInputCaptcha(""); - // }; useEffect(() => { generateCaptcha(); @@ -52,225 +33,201 @@ export default function Changetransactionpwd() { setCaptchaError(''); }; - async function handleLogin(e: React.FormEvent) { + async function handleSetTransactionPassword(e: React.FormEvent) { e.preventDefault(); - const onlyDigit = /^\d{11}$/; - if (!onlyDigit.test(CIF)) { - setError('Input value must be 11 digit'); - } - - if (inputCaptcha !== captcha) { + const pwdRegex = /^(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/; + if (!password || !confirmPassword) { notifications.show({ withBorder: true, color: "red", - title: "Captcha Error", - message: "Please enter the correct captcha", + title: "Both password fields are required.", + message: "Both password fields are required.", + autoClose: 5000, + }); + return; + // alert("Both password fields are required."); + } else if (password !== confirmPassword) { + // alert("Passwords do not match."); + notifications.show({ + withBorder: true, + color: "red", + title: "Passwords do not match.", + message: "Passwords do not match.", autoClose: 5000, }); return; } - - if (CIF === "30022497139" && psw === "SecurePass123!") { - const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30"; - localStorage.setItem("customerNumber", CIF); - localStorage.setItem("password", psw); - localStorage.setItem("access_token", token); - router.push("/home"); - } else { - // SetCIF(''); - // SetPsw(''); - // setCaptcha(''); + else if (!pwdRegex.test(password)) { + // alert("Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long."); notifications.show({ withBorder: true, color: "red", - title: "Wrong User Id or Password", - message: "Wrong User Id or Password", + title: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", + message: "Password must contain at least 1 capital letter, 1 number, 1 special character, and be at least 8 characters long.", autoClose: 5000, }); + return; + } + else if (captchaInput !== captcha) { + setCaptchaError("Incorrect CAPTCHA."); + return; + } + const token = localStorage.getItem("access_token"); + const response = await fetch('api/auth/transaction_password', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${token}` + }, + body: JSON.stringify({ + transaction_password: password, + }), + }); + const data = await response.json(); + if (response.ok) { + console.log(data); + notifications.show({ + withBorder: true, + color: "green", + title: "Transaction Password has been set", + message: "Transaction Password has been set", + autoClose: 5000, + }); + router.push("/login"); + } + else { + notifications.show({ + withBorder: true, + color: "red", + title: "Please try again later ", + message: "Please try again later ", + autoClose: 5000, + }); + router.push("/login"); } } - return ( - -
- - ebanking - -
- {/*
-
- ebanking -
- - Change User Login Password -
- - - - + useEffect(() => { + const token = localStorage.getItem("access_token"); + if (!token) { + SetAuthorized(false); + router.push("/login"); + } + else { + SetAuthorized(true); + } + }, []); -

- - - Note: Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. - - -
-
*/} - - Change Password Image - - - Set Transaction Password -
- e.preventDefault()} - onPaste={(e) => e.preventDefault()} - onCut={(e) => e.preventDefault()} - /> - e.preventDefault()} - onPaste={(e) => e.preventDefault()} - onCut={(e) => e.preventDefault()} - /> - {/* */} - - {/* CAPTCHA */} -
- -
- - -
- setCaptchaInput(e.currentTarget.value)} + if (authorized) { + return ( + +
+ + ebanking + +
+ + Change Password Image + + + Set Transaction Password + + setPassword(e.currentTarget.value)} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} /> - {captchaError &&

{captchaError}

} -
+ setConfirmPassword(e.currentTarget.value)} + onCopy={(e) => e.preventDefault()} + onPaste={(e) => e.preventDefault()} + onCut={(e) => e.preventDefault()} + /> + {/* CAPTCHA */} +
+ +
+ + +
+ setCaptchaInput(e.currentTarget.value)} + required + /> + {captchaError &&

{captchaError}

} +
+ + - +

+ - -

- - - Note: Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. - - - + }} + > + + Note: Password will contains minimum one alphabet, one digit, one special symbol and total 8 charecters. + +
+ + - - - - © 2025 KCC Bank. All rights reserved. {" "} + + + © 2025 KCC Bank. All rights reserved. {" "} - - + + +
-
- - ); + + ); + } } diff --git a/src/app/captcha.tsx b/src/app/captcha.tsx new file mode 100644 index 0000000..89f846e --- /dev/null +++ b/src/app/captcha.tsx @@ -0,0 +1,4 @@ +export async function generateCaptcha(length = 6) { + const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join(""); +} \ No newline at end of file diff --git a/src/app/image/logo.jpg b/src/app/image/logo.jpg index 38c9829..126fb76 100644 Binary files a/src/app/image/logo.jpg and b/src/app/image/logo.jpg differ diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 62a2ea3..1e72ab9 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -8,12 +8,7 @@ import NextImage from "next/image"; import logo from '@/app/image/logo.jpg'; import frontPage from '@/app/image/ib_front_page.jpg'; import dynamic from 'next/dynamic'; - - -function generateCaptcha(length = 6) { - const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - return Array.from({ length }, () => chars[Math.floor(Math.random() * chars.length)]).join(""); -} +import { generateCaptcha } from '@/app/captcha'; export default function Login() { const router = useRouter(); @@ -24,21 +19,29 @@ export default function Login() { const [inputCaptcha, setInputCaptcha] = useState(""); const [isLogging, setIsLogging] = useState(false); const ClientCarousel = dynamic(() => import('./clientCarousel'), { ssr: false }); - localStorage.setItem("password", "SecurePass123!"); - localStorage.setItem("Tpin_setup", "F"); useEffect(() => { - setCaptcha(generateCaptcha()); + const loadCaptcha = async () => { + const newCaptcha = await generateCaptcha(); + setCaptcha(newCaptcha); + }; + loadCaptcha(); }, []); const regenerateCaptcha = () => { - setCaptcha(generateCaptcha()); + // setCaptcha(generateCaptcha()); + const loadCaptcha = async () => { + const newCaptcha = await generateCaptcha(); + setCaptcha(newCaptcha); + }; + loadCaptcha(); setInputCaptcha(""); }; async function handleLogin(e: React.FormEvent) { e.preventDefault(); setIsLogging(false); + const onlyDigit = /^\d{11}$/; if (!onlyDigit.test(CIF)) { setError('Input value must be 11 digit'); @@ -54,25 +57,30 @@ export default function Login() { }); return; } - - if (CIF === "30022497139" && psw === localStorage.getItem("password")) { - const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.KMUFsIDTnFmyG3nMiGM6H9FNFUROf3wh7SmqJp-QV30"; - // localStorage.setItem("customerNumber", CIF); - // localStorage.setItem("password", psw); - // console.log("Tithi:", localStorage.getItem("password")); - console.log("Tithi:", localStorage.getItem("Tpin_setup")); + const response = await fetch('api/auth/login', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + customerNo: CIF, + password: psw, + }), + }); + const data = await response.json(); + if (response.ok) { + console.log(data); + const token = data.token; localStorage.setItem("access_token", token); - setIsLogging(true); - // if (localStorage.getItem("Tpin_setup") === 'F') - // router.push("/ChangePassword"); - // else - router.push("/home"); - } else { - // SetCIF(''); - // SetPsw(''); - // setCaptcha(''); - console.log("Tithi:", localStorage.getItem("password")); - console.log("Tithi:", localStorage.getItem("Tpin_setup")); + if (data.FirstTimeLogin === true) { + router.push("/ChangePassword") + } + else { + router.push("/home"); + } + + } + else { notifications.show({ withBorder: true, color: "red", @@ -160,16 +168,6 @@ export default function Login() { style={{ width: "100%", height: "100%" }} />
- {/*
*/} - + Security Notes :

When you Login,Your User Id and Password travels in an encrypted and highly secured mode .