Skip to content

Commit

Permalink
feat(commands): add PWD EDIT command
Browse files Browse the repository at this point in the history
fix(auth): remove zero bytes allocation problem for `passwords`
fix(ci): add missing `uses` field
feat(commands): add permissions field to CLIENT INFO command
  • Loading branch information
aloima committed Nov 5, 2024
1 parent 63affa6 commit 7e1f124
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 73 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/c.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ jobs:
steps:
- uses: actions/checkout@v4

- name: make
- name: Build
run: make

- name: On release
uses: startsWith(github.ref, 'refs/tags/')
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
with:
files: telly
26 changes: 24 additions & 2 deletions docs/COMMANDS.md
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,29 @@ This document provides a detailed description of all the available commands. Eac
**Behavior**:
* If current using password by client do not have a permissions in `permissions`, throws an error.
* If there is an invalid permission in `permissions`, throws an error.
* If `password` is already exist, throws an error.
* If `password` already exists, throws an error.

**Arguments**:
- **password**: Password value
- **permissions**: For permissions, look at [AUTH.md](./AUTH.md). Each character represents a permissions:
+ `r` => `P_READ`
+ `w` => `P_WRITE`
+ `c` => `P_CLIENT`
+ `o` => `P_CONFIG`
+ `a` => `P_AUTH`
+ `s` => `P_SERVER`

#### EDIT
**Syntax**: `PWD EDIT password permissions`
**Description**: Edits a password permissions.
**Since**: `0.1.7`
**Time complexity**: `O(N) where N is permissions length`
**Permissions**: None
**Returns**: `OK`
**Behavior**:
* If current using password by client do not have a permissions in `permissions`, throws an error.
* If there is an invalid permission in `permissions`, throws an error.
* If `password` does not exist, throws an error.

**Arguments**:
- **password**: Password value
Expand Down Expand Up @@ -561,7 +583,7 @@ INCR user_age
* If the key is exist, new value will be overwritten.

**Arguments**:
- **NX**: Only set if the key does not already exist.
- **NX**: Only set if the key does not exist.
- **XX**: Only set if the key exists.
- **GET**: Returns the old value if it existed.

Expand Down
1 change: 1 addition & 0 deletions headers/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ void free_passwords();
void add_password(struct Client *client, const string_t data, const uint8_t permissions);
bool remove_password(struct Client *executor, const char *value);
int32_t where_password(const char *value);
struct Password *get_password(const char *value);
bool edit_password(const char *value, const uint32_t permissions);
/* /AUTH */

Expand Down
26 changes: 25 additions & 1 deletion src/commands/generic/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <ctype.h>
#include <time.h>

static void run(struct Client *client, commanddata_t *command, __attribute__((unused)) struct Password *password) {
Expand Down Expand Up @@ -34,6 +35,28 @@ static void run(struct Client *client, commanddata_t *command, __attribute__((un
break;
}

char permissions[44];
permissions[0] = '\0';

{
const uint8_t value = client->password->permissions;
uint32_t length = 0;

if (value == 0) {
memcpy(permissions, "None", 5);
} else {
if (value & P_READ) strcat(permissions, "read, "), length += 6;
if (value & P_WRITE) strcat(permissions, "write, "), length += 7;
if (value & P_CLIENT) strcat(permissions, "client, "), length += 8;
if (value & P_CONFIG) strcat(permissions, "config, "), length += 8;
if (value & P_AUTH) strcat(permissions, "auth, "), length += 6;
if (value & P_SERVER) strcat(permissions, "server, "), length += 8;

permissions[0] = toupper(permissions[0]);
permissions[length - 2] = '\0';
}
}

char buf[512];
const size_t buf_len = sprintf(buf, (
"ID: %d\r\n"
Expand All @@ -43,7 +66,8 @@ static void run(struct Client *client, commanddata_t *command, __attribute__((un
"Library name: %s\r\n"
"Library version: %s\r\n"
"Protocol: %s\r\n"
), client->id, client->connfd, ctime(&client->connected_at), client->command->name, lib_name, lib_ver, protocol);
"Permissions: %s\r\n"
), client->id, client->connfd, ctime(&client->connected_at), client->command->name, lib_name, lib_ver, protocol, permissions);

char res[1024];
const size_t nbytes = sprintf(res, "$%ld\r\n%s\r\n", buf_len, buf);
Expand Down
122 changes: 79 additions & 43 deletions src/commands/generic/pwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,51 @@ static void generate_random(char *dest, size_t length) {
*dest = '\0';
}

static uint8_t read_permissions_value(struct Client *client, char *permissions_value) {
uint8_t permissions = 0;
char c;

while ((c = *permissions_value) != '\0') {
switch (c) {
case 'r':
permissions |= P_READ;
break;

case 'w':
permissions |= P_WRITE;
break;

case 'c':
permissions |= P_CLIENT;
break;

case 'o':
permissions |= P_CONFIG;
break;

case 'a':
permissions |= P_AUTH;
break;

case 's':
permissions |= P_SERVER;
break;

default: {
char buf[27];
sprintf(buf, "-Invalid permission: '%c'\r\n", c);

_write(client, buf, 26);
return 0;
}
}

permissions_value += 1;
}

return permissions;
}

static void run(struct Client *client, commanddata_t *command, struct Password *password) {
if (command->arg_count == 0) {
WRONG_ARGUMENT_ERROR(client, "AUTH", 4);
Expand All @@ -37,48 +82,7 @@ static void run(struct Client *client, commanddata_t *command, struct Password *

const string_t data = command->args[1];
char *permissions_value = command->args[2].value;
uint8_t permissions = 0;

char c;

while ((c = *permissions_value) != '\0') {
switch (c) {
case 'r':
permissions |= P_READ;
break;

case 'w':
permissions |= P_WRITE;
break;

case 'c':
permissions |= P_CLIENT;
break;

case 'o':
permissions |= P_CONFIG;
break;

case 'a':
permissions |= P_AUTH;
break;

case 's':
permissions |= P_SERVER;
break;

default: {
char buf[27];
sprintf(buf, "-Invalid permission: '%c'\r\n", c);

_write(client, buf, 26);
return;
}
}

permissions_value += 1;
}

const uint8_t permissions = read_permissions_value(client, permissions_value);
const uint8_t not_has = ~password->permissions & permissions;

if (not_has) {
Expand All @@ -90,7 +94,32 @@ static void run(struct Client *client, commanddata_t *command, struct Password *
add_password(client, data, permissions);
WRITE_OK(client);
} else {
_write(client, "-This password is already exist\r\n", 33);
_write(client, "-This password already exists\r\n", 31);
}
} if (streq(subcommand, "EDIT")) {
if (command->arg_count != 3) {
WRONG_ARGUMENT_ERROR(client, "AUTH EDIT", 9);
return;
}

const char *value = command->args[1].value;
char *permissions_value = command->args[2].value;

struct Password *target = get_password(value);

if (target) {
const uint8_t permissions = read_permissions_value(client, permissions_value);
const uint8_t not_has = ~password->permissions & permissions;

if (not_has) {
_write(client, "-Tried to give permissions your password do not have\r\n", 54);
return;
}

target->permissions = permissions;
WRITE_OK(client);
} else {
_write(client, "-This password does not exist\r\n", 31);
}
} else if (streq(subcommand, "REMOVE")) {
if (command->arg_count != 2) {
Expand All @@ -99,6 +128,7 @@ static void run(struct Client *client, commanddata_t *command, struct Password *
}

const char *value = command->args[1].value;

if (remove_password(client, value)) WRITE_OK(client);
else {
_write(client, "-This password cannot be found\r\n", 32);
Expand All @@ -124,6 +154,12 @@ static struct Subcommand subcommands[] = {
.since = "0.1.7",
.complexity = "O(N) where N is permissions length"
},
(struct Subcommand) {
.name = "EDIT",
.summary = "Edits a password permissions.",
.since = "0.1.7",
.complexity = "O(N) where N is permissions length"
},
(struct Subcommand) {
.name = "REMOVE",
.summary = "Removes a password.",
Expand Down
70 changes: 45 additions & 25 deletions src/server/auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -16,36 +16,43 @@ uint32_t get_password_count() {
return password_count;
}

static void get_password_from_file(const int fd, const uint32_t i) {
struct Password *password = (passwords[i] = malloc(sizeof(struct Password)));
string_t *data = &password->data;

// String length specifier
{
uint8_t first;
read(fd, &first, 1);

const uint8_t byte_count = first >> 6;
data->len = 0;
read(fd, &data->len, byte_count);

data->len = (data->len << 6) | (first & 0b111111);
data->value = malloc(data->len + 1);
}

read(fd, data->value, data->len);
data->value[data->len] = '\0';

read(fd, &password->permissions, 1);
}

off_t get_authorization_from_file(const int fd) {
lseek(fd, 10, SEEK_SET);

uint8_t password_count_byte_count;
read(fd, &password_count_byte_count, 1);
read(fd, &password_count, password_count_byte_count);

passwords = malloc(password_count * sizeof(struct Password *));

for (uint32_t i = 0; i < password_count; ++i) {
struct Password *password = (passwords[i] = malloc(sizeof(struct Password)));
string_t *data = &password->data;

// String length specifier
{
uint8_t first;
read(fd, &first, 1);

const uint8_t byte_count = first >> 6;
data->len = 0;
read(fd, &data->len, byte_count);
if (password_count != 0) {
passwords = malloc(password_count * sizeof(struct Password *));
get_password_from_file(fd, 0);

data->len = (data->len << 6) | (first & 0b111111);
data->value = malloc(data->len + 1);
for (uint32_t i = 1; i < password_count; ++i) {
get_password_from_file(fd, i);
}

read(fd, data->value, data->len);
data->value[data->len] = '\0';

read(fd, &password->permissions, 1);
}

return lseek(fd, 0, SEEK_CUR);
Expand All @@ -59,6 +66,15 @@ int32_t where_password(const char *value) {
return -1;
}

struct Password *get_password(const char *value) {
for (uint32_t i = 0; i < password_count; ++i) {
struct Password *password = passwords[i];
if (streq(value, password->data.value)) return password;
}

return NULL;
}

bool edit_password(const char *value, const uint32_t permissions) {
for (uint32_t i = 0; i < password_count; ++i) {
struct Password *password = passwords[i];
Expand Down Expand Up @@ -99,11 +115,15 @@ void free_password(struct Password *password) {
}

void free_passwords() {
for (uint32_t i = 0; i < password_count; ++i) {
free_password(passwords[i]);
}
if (password_count != 0) {
free_password(passwords[0]);

free(passwords);
for (uint32_t i = 1; i < password_count; ++i) {
free_password(passwords[i]);
}

free(passwords);
}
}

bool remove_password(struct Client *executor, const char *value) {
Expand Down

0 comments on commit 7e1f124

Please sign in to comment.