Skip to content

Commit a72f9ef

Browse files
authored
Merge pull request #7 from amfoss/develop
Major feature and other changes.
2 parents 4fcd2cc + 92eab6a commit a72f9ef

10 files changed

+84
-14
lines changed

.github/workflows/deploy.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,7 @@ jobs:
1212
steps:
1313
- uses: shuttle-hq/deploy-action@main
1414
with:
15-
deploy-key: ${{ secrets.SHUTTLE_API_KEY }}
1615
name: "root"
16+
deploy-key: ${{ secrets.SHUTTLE_API_KEY }}
17+
secrets: |
18+
ROOT_SECRET = '${{ secrets.ROOT_SECRET }}'

.github/workflows/shuttle-run.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,8 @@ jobs:
1010
- name: Checkout
1111
uses: actions/checkout@v4
1212

13-
- name: Run shuttle project locally.
13+
- name: Run shuttle project locally.
1414
uses: ivinjabraham/shuttle-run@v1.1
15+
with:
16+
secrets: |
17+
ROOT_SECRET = '${{ secrets.ROOT_SECRET }}'

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,6 @@ shuttle-runtime = "0.46.0"
1414
shuttle-shared-db = { version = "0.46.0", features = ["postgres", "sqlx"] }
1515
sqlx = { version = "0.7.1", features = ["chrono"] }
1616
tokio = "1.28.2"
17+
hmac = "0.12.1"
18+
sha2 = "0.10.8"
19+
hex = "0.4.3"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE Attendance RENAME COLUMN ispresent TO is_prresent;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE Attendance RENAME COLUMN is_prresent TO is_present;

migrations/20240813132052_rename_present_to_is_present.sql

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/db/member.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ pub struct Member {
1313
pub email: String,
1414
pub sex: String,
1515
pub year: i32,
16+
pub macaddress: String,
1617
}

src/graphql/mutations.rs

Lines changed: 60 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
use async_graphql::{Context, Object};
2+
use ::chrono::Local;
23
use chrono::{NaiveDate, NaiveTime};
34
use sqlx::PgPool;
45
use sqlx::types::chrono;
56
use std::sync::Arc;
7+
use hmac::{Hmac,Mac};
8+
use sha2::Sha256;
9+
10+
11+
type HmacSha256 = Hmac<Sha256>;
612

713
use crate::db::{member::Member, attendance::Attendance};
814

@@ -20,19 +26,24 @@ impl MutationRoot {
2026
hostel: String,
2127
email: String,
2228
sex: String,
23-
year: i32
29+
year: i32,
30+
macaddress: String,
31+
2432
) -> Result<Member, sqlx::Error> {
2533
let pool = ctx.data::<Arc<PgPool>>().expect("Pool not found in context");
2634

35+
36+
2737
let member = sqlx::query_as::<_, Member>(
28-
"INSERT INTO Member (rollno, name, hostel, email, sex, year) VALUES ($1, $2, $3, $4, $5, $6) RETURNING *"
38+
"INSERT INTO Member (rollno, name, hostel, email, sex, year, macaddress) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *"
2939
)
3040
.bind(rollno)
3141
.bind(name)
3242
.bind(hostel)
3343
.bind(email)
3444
.bind(sex)
3545
.bind(year)
46+
.bind(macaddress)
3647
.fetch_one(pool.as_ref())
3748
.await?;
3849

@@ -42,22 +53,29 @@ impl MutationRoot {
4253

4354
//Mutation for adding attendance to the Attendance table
4455
async fn add_attendance(
56+
4557
&self,
58+
4659
ctx: &Context<'_>,
4760
id: i32,
4861
date: NaiveDate,
4962
timein: NaiveTime,
5063
timeout: NaiveTime,
64+
is_present: bool,
65+
5166
) -> Result<Attendance, sqlx::Error> {
5267
let pool = ctx.data::<Arc<PgPool>>().expect("Pool not found in context");
5368

69+
5470
let attendance = sqlx::query_as::<_, Attendance>(
55-
"INSERT INTO Attendance (id, date, timein, timeout) VALUES ($1, $2, $3, $4) RETURNING *"
71+
"INSERT INTO Attendance (id, date, timein, timeout, is_present) VALUES ($1, $2, $3, $4, $5) RETURNING *"
5672
)
73+
5774
.bind(id)
5875
.bind(date)
5976
.bind(timein)
6077
.bind(timeout)
78+
.bind(is_present)
6179
.fetch_one(pool.as_ref())
6280
.await?;
6381

@@ -70,17 +88,53 @@ impl MutationRoot {
7088
id: i32,
7189
date: NaiveDate,
7290
is_present: bool,
91+
hmac_signature: String,
7392
) -> Result<Attendance,sqlx::Error> {
93+
7494
let pool = ctx.data::<Arc<PgPool>>().expect("Pool not found in context");
7595

96+
let secret_key = ctx.data::<String>().expect("HMAC secret not found in context");
97+
98+
let mut mac = HmacSha256::new_from_slice(secret_key.as_bytes()).expect("HMAC can take key of any size");
99+
100+
let message = format!("{}{}{}", id, date, is_present);
101+
mac.update(message.as_bytes());
102+
103+
let expected_signature = mac.finalize().into_bytes();
104+
105+
106+
// Convert the received HMAC signature from the client to bytes for comparison
107+
let received_signature = hex::decode(hmac_signature)
108+
.map_err(|_| sqlx::Error::Protocol("Invalid HMAC signature".into()))?;
109+
110+
111+
if expected_signature.as_slice() != received_signature.as_slice() {
112+
113+
return Err(sqlx::Error::Protocol("HMAC verification failed".into()));
114+
}
115+
116+
117+
118+
119+
let current_time = Local::now().time();
120+
76121
let attendance = sqlx::query_as::<_, Attendance>(
77-
"UPDATE Attendance SET is_present = $1 WHERE id = $2 AND date = $3 RETURNING *"
122+
"
123+
UPDATE Attendance
124+
SET
125+
timein = CASE WHEN timein = '00:00:00' THEN $1 ELSE timein END,
126+
timeout = $1,
127+
is_present = $2
128+
WHERE id = $3 AND date = $4
129+
RETURNING *
130+
"
78131
)
132+
.bind(current_time)
79133
.bind(is_present)
80134
.bind(id)
81-
.bind(date)
135+
.bind(date)
82136
.fetch_one(pool.as_ref())
83-
.await?;
137+
.await?;
84138

85139
Ok(attendance)
86140
}

src/main.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11

22
use std::{env, sync::Arc};
33
use tokio::task;
4-
use tokio::time::{sleep, sleep_until, Instant};
4+
use tokio::time::{ sleep_until, Instant};
55
use std::time::Duration;
66
use async_graphql_axum::GraphQL;
77
use axum::{routing::get, Router};
88
use chrono::{ Local, NaiveTime};
9-
use db::attendance::Attendance;
9+
1010
use db::member::Member;
1111
use sqlx::PgPool;
1212
use async_graphql::{ Schema, EmptySubscription};
13-
13+
use shuttle_runtime::SecretStore;
1414
use crate::graphql::mutations::MutationRoot;
1515
use crate::graphql::query::QueryRoot;
1616
use crate::routes::graphiql;
@@ -22,21 +22,24 @@ mod routes;
2222
#[derive(Clone)]
2323
struct MyState {
2424
pool: Arc<PgPool>,
25+
secret_key: String,
2526
}
2627

2728
//Main method
2829
#[shuttle_runtime::main]
29-
async fn main(#[shuttle_shared_db::Postgres] pool: PgPool) -> shuttle_axum::ShuttleAxum {
30+
async fn main(#[shuttle_shared_db::Postgres] pool: PgPool,#[shuttle_runtime::Secrets] secrets: SecretStore,) -> shuttle_axum::ShuttleAxum {
3031
env::set_var("PGOPTIONS", "-c ignore_version=true");
3132

3233
sqlx::migrate!().run(&pool).await.expect("Failed to run migrations");
3334

3435
let pool = Arc::new(pool);
36+
let secret_key = secrets.get("ROOT_SECRET").expect("ROOT_SECRET not found");
3537
let schema = Schema::build(QueryRoot, MutationRoot, EmptySubscription)
3638
.data(pool.clone())
39+
.data(secret_key.clone()) //
3740
.finish();
3841

39-
let state = MyState { pool: pool.clone() };
42+
let state = MyState { pool: pool.clone() , secret_key: secret_key.clone()};
4043

4144
let router = Router::new()
4245
.route("/", get(graphiql).post_service(GraphQL::new(schema.clone())))

0 commit comments

Comments
 (0)