diff --git a/src/database/channel.rs b/src/database/channel.rs
index 2b10748aaa06cb8600fd3378c74783c9d9d9ebf1..309b59886f61a194a10af3fc6fc582d68b6d766d 100644
--- a/src/database/channel.rs
+++ b/src/database/channel.rs
@@ -10,13 +10,18 @@ pub struct Channel {
     pub last_message: Option<String>,
 
     // for Direct Messages
-    pub recipients: Option<Vec<String>>,
     pub active: Option<bool>,
 
+    // for DMs / GDMs
+    pub recipients: Option<Vec<String>>,
+
+    // for GDMs
+    pub owner: Option<String>,
+
     // for Guilds
-    pub name: Option<String>,
     pub guild: Option<String>,
 
     // for Guilds and Group DMs
+    pub name: Option<String>,
     pub description: Option<String>,
 }
diff --git a/src/database/guild.rs b/src/database/guild.rs
index 5279061cddac02b3851a758a0cc68751e0346300..3fb73f17e855ecd446dc79d67912c8842a701fee 100644
--- a/src/database/guild.rs
+++ b/src/database/guild.rs
@@ -7,7 +7,7 @@ use mongodb::options::FindOneOptions;
 pub fn find_member_permissions<C: Into<Option<String>>>(
     id: String,
     guild: String,
-    channel: C,
+    _channel: C,
 ) -> u32 {
     let col = get_collection("guilds");
 
@@ -46,6 +46,7 @@ pub fn find_member_permissions<C: Into<Option<String>>>(
 #[derive(Serialize, Deserialize, Debug)]
 pub struct Member {
     pub id: String,
+    pub nickname: String,
 }
 
 #[derive(Serialize, Deserialize, Debug)]
diff --git a/src/database/permissions.rs b/src/database/permissions.rs
index 1a31abf764fc004a31f14922b74820040f062660..8e57666726d5fa27978b605cdea86dcadb7d0261 100644
--- a/src/database/permissions.rs
+++ b/src/database/permissions.rs
@@ -10,11 +10,11 @@ use num_enum::TryFromPrimitive;
 #[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
 #[repr(u8)]
 pub enum Relationship {
-    FRIEND = 0,
-    OUTGOING = 1,
-    INCOMING = 2,
-    BLOCKED = 3,
-    BLOCKEDOTHER = 4,
+    Friend = 0,
+    Outgoing = 1,
+    Incoming = 2,
+    Blocked = 3,
+    BlockedOther = 4,
     NONE = 5,
     SELF = 6,
 }
@@ -22,16 +22,16 @@ pub enum Relationship {
 #[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
 #[repr(u32)]
 pub enum Permission {
-    ACCESS = 1,
-    CREATE_INVITE = 2,
-    KICK_MEMBERS = 4,
-    BAN_MEMBERS = 8,
-    READ_MESSAGES = 16,
-    SEND_MESSAGES = 32,
-    MANAGE_MESSAGES = 64,
-    MANAGE_CHANNELS = 128,
-    MANAGE_SERVER = 256,
-    MANAGE_ROLES = 512,
+    Access = 1,
+    CreateInvite = 2,
+    KickMembers = 4,
+    BanMembers = 8,
+    ReadMessages = 16,
+    SendMessages = 32,
+    ManageMessages = 64,
+    ManageChannels = 128,
+    ManageServer = 256,
+    ManageRoles = 512,
 }
 
 bitfield! {
@@ -62,11 +62,11 @@ pub fn get_relationship_internal(
         for entry in arr {
             if entry.id == target_id {
                 match entry.status {
-                    0 => return Relationship::FRIEND,
-                    1 => return Relationship::OUTGOING,
-                    2 => return Relationship::INCOMING,
-                    3 => return Relationship::BLOCKED,
-                    4 => return Relationship::BLOCKEDOTHER,
+                    0 => return Relationship::Friend,
+                    1 => return Relationship::Outgoing,
+                    2 => return Relationship::Incoming,
+                    3 => return Relationship::Blocked,
+                    4 => return Relationship::BlockedOther,
                     _ => return Relationship::NONE,
                 }
             }
@@ -132,7 +132,7 @@ impl PermissionCalculator {
             None
         };
 
-        let mut permissions = 0;
+        let mut permissions: u32 = 0;
         if let Some(guild) = guild {
             if let Some(_data) = guild.fetch_data_given(
                 doc! {
@@ -148,14 +148,13 @@ impl PermissionCalculator {
                     return u32::MAX;
                 }
 
-                permissions = guild.default_permissions;
+                permissions = guild.default_permissions as u32;
             }
         }
 
         if let Some(channel) = &self.channel {
             match channel.channel_type {
                 0 => {
-                    // ? check user is part of the channel
                     if let Some(arr) = &channel.recipients {
                         let mut other_user = "";
                         for item in arr {
@@ -170,8 +169,8 @@ impl PermissionCalculator {
                         let relationship =
                             get_relationship_internal(&self.user.id, &other_user, &relationships);
 
-                        if relationship == Relationship::BLOCKED
-                            || relationship == Relationship::BLOCKEDOTHER
+                        if relationship == Relationship::Blocked
+                            || relationship == Relationship::BlockedOther
                         {
                             permissions = 1;
                         } else if has_mutual_connection(self.user.id, other_user.to_string()) {
@@ -179,7 +178,22 @@ impl PermissionCalculator {
                         }
                     }
                 }
-                1 => unreachable!(),
+                1 => {
+                    if let Some(id) = &channel.owner {
+                        if &self.user.id == id {
+                            return u32::MAX;
+                        }
+                    }
+
+                    if let Some(arr) = &channel.recipients {
+                        for item in arr {
+                            if item == &self.user.id {
+                                permissions = 49;
+                                break;
+                            }
+                        }
+                    }
+                }
                 2 => {
                     // nothing implemented yet
                 }
@@ -187,7 +201,7 @@ impl PermissionCalculator {
             }
         }
 
-        permissions as u32
+        permissions
     }
 
     pub fn as_permission(self) -> MemberPermissions<[u32; 1]> {
diff --git a/src/guards/auth.rs b/src/guards/auth.rs
index 0d3047024c08a3f6a218e65d82331264e642a60b..9f17f120a318dc30cccd1d7f2ccf13941977509d 100644
--- a/src/guards/auth.rs
+++ b/src/guards/auth.rs
@@ -16,6 +16,33 @@ pub struct UserRef {
 }
 
 impl UserRef {
+    pub fn from(id: String) -> Option<UserRef> {
+        match database::get_collection("users").find_one(
+            doc! { "_id": id },
+            FindOneOptions::builder()
+                .projection(doc! {
+                    "_id": 1,
+                    "username": 1,
+                    "email_verification.verified": 1,
+                })
+                .build(),
+        ) {
+            Ok(result) => match result {
+                Some(doc) => Some(UserRef {
+                    id: doc.get_str("_id").unwrap().to_string(),
+                    username: doc.get_str("username").unwrap().to_string(),
+                    email_verified: doc
+                        .get_document("email_verification")
+                        .unwrap()
+                        .get_bool("verified")
+                        .unwrap(),
+                }),
+                None => None,
+            },
+            Err(_) => None,
+        }
+    }
+
     pub fn fetch_data(&self, projection: Document) -> Option<Document> {
         database::get_collection("users")
             .find_one(
@@ -126,30 +153,8 @@ impl<'r> FromParam<'r> for UserRef {
     type Error = &'r RawStr;
 
     fn from_param(param: &'r RawStr) -> Result<Self, Self::Error> {
-        let col = database::get_db().collection("users");
-        let result = database::get_collection("users")
-            .find_one(
-                doc! { "_id": param.to_string() },
-                FindOneOptions::builder()
-                    .projection(doc! {
-                        "_id": 1,
-                        "username": 1,
-                        "email_verification.verified": 1,
-                    })
-                    .build(),
-            )
-            .unwrap();
-
-        if let Some(user) = result {
-            Ok(UserRef {
-                id: user.get_str("_id").unwrap().to_string(),
-                username: user.get_str("username").unwrap().to_string(),
-                email_verified: user
-                    .get_document("email_verification")
-                    .unwrap()
-                    .get_bool("verified")
-                    .unwrap(),
-            })
+        if let Some(user) = UserRef::from(param.to_string()) {
+            Ok(user)
         } else {
             Err(param)
         }
diff --git a/src/guards/channel.rs b/src/guards/channel.rs
index 254ded4b3c750d45f7b58c557489b030b0aae034..11f294308889da6e65e52105c4bf50d3fcff52c9 100644
--- a/src/guards/channel.rs
+++ b/src/guards/channel.rs
@@ -36,6 +36,7 @@ pub struct ChannelRef {
     // information required for permission calculations
     pub recipients: Option<Vec<String>>,
     pub guild: Option<String>,
+    pub owner: Option<String>,
 }
 
 impl ChannelRef {
diff --git a/src/routes/account.rs b/src/routes/account.rs
index be323057ec47c7938d4772e6b90e19506237f8ac..46b747118f20f6c7cff9c316cc8df49470fb7b63 100644
--- a/src/routes/account.rs
+++ b/src/routes/account.rs
@@ -7,7 +7,7 @@ use bson::{bson, doc, from_bson, Bson::UtcDatetime};
 use chrono::prelude::*;
 use database::user::User;
 use rand::{distributions::Alphanumeric, Rng};
-use rocket_contrib::json::{Json, JsonValue};
+use rocket_contrib::json::Json;
 use serde::{Deserialize, Serialize};
 use ulid::Ulid;
 use validator::validate_email;
@@ -167,7 +167,7 @@ pub fn resend_email(info: Json<Resend>) -> Response {
             doc! { "email_verification.target": info.email.clone() },
             None,
         )
-        .expect("Failed user lookup")
+        .expect("Failed user lookup.")
     {
         let user: User = from_bson(bson::Bson::Document(u)).expect("Failed to unwrap user.");
         let ev = user.email_verification;
diff --git a/src/routes/channel.rs b/src/routes/channel.rs
index 5c92f3f2287e037c63cc23ab06dde43783ae02d1..e74f65eb1e2a1e37028968e419e1d3d1315a6e32 100644
--- a/src/routes/channel.rs
+++ b/src/routes/channel.rs
@@ -1,15 +1,21 @@
 use super::Response;
-use crate::database::{self, message::Message, Permission, PermissionCalculator};
+use crate::database::{
+    self, get_relationship_internal, message::Message, Permission, PermissionCalculator,
+    Relationship,
+};
 use crate::guards::auth::UserRef;
 use crate::guards::channel::ChannelRef;
 
-use bson::{bson, doc, from_bson, Bson::UtcDatetime};
+use bson::{bson, doc, from_bson, Bson, Bson::UtcDatetime};
 use chrono::prelude::*;
+use hashbrown::HashSet;
 use num_enum::TryFromPrimitive;
 use rocket_contrib::json::Json;
 use serde::{Deserialize, Serialize};
 use ulid::Ulid;
 
+const MAXGROUPSIZE: usize = 50;
+
 #[derive(Debug, TryFromPrimitive)]
 #[repr(usize)]
 pub enum ChannelType {
@@ -32,6 +38,71 @@ macro_rules! with_permissions {
     }};
 }
 
+#[derive(Serialize, Deserialize)]
+pub struct CreateGroup {
+    name: String,
+    nonce: String,
+    users: Vec<String>,
+}
+
+/// create a new group
+#[post("/create", data = "<info>")]
+pub fn create_group(user: UserRef, info: Json<CreateGroup>) -> Response {
+    let name: String = info.name.chars().take(32).collect();
+    let nonce: String = info.nonce.chars().take(32).collect();
+
+    let mut set = HashSet::new();
+    set.insert(user.id.clone());
+    for item in &info.users {
+        set.insert(item.clone());
+    }
+
+    if set.len() > MAXGROUPSIZE {
+        return Response::BadRequest(json!({ "error": "Maximum group size is 50." }));
+    }
+
+    let col = database::get_collection("channels");
+    if let Some(_) = col.find_one(doc! { "nonce": nonce.clone() }, None).unwrap() {
+        return Response::BadRequest(json!({ "error": "Group already created!" }));
+    }
+
+    let relationships = user.fetch_relationships();
+
+    let mut users = vec![];
+    for item in set {
+        if let Some(target) = UserRef::from(item) {
+            if get_relationship_internal(&user.id, &target.id, &relationships)
+                != Relationship::Friend
+            {
+                return Response::BadRequest(json!({ "error": "Not friends with user(s)." }));
+            }
+
+            users.push(Bson::String(target.id));
+        } else {
+            return Response::BadRequest(json!({ "error": "Specified non-existant user(s)." }));
+        }
+    }
+
+    let id = Ulid::new().to_string();
+    if col
+        .insert_one(
+            doc! {
+                "_id": id.clone(),
+                "nonce": nonce,
+                "type": ChannelType::GROUPDM as u32,
+                "recipients": users,
+                "name": name,
+            },
+            None,
+        )
+        .is_ok()
+    {
+        Response::Success(json!({ "id": id }))
+    } else {
+        Response::InternalServerError(json!({ "error": "Failed to create guild channel." }))
+    }
+}
+
 /// fetch channel information
 #[get("/<target>")]
 pub fn channel(user: UserRef, target: ChannelRef) -> Option<Response> {
@@ -71,20 +142,25 @@ pub fn delete(user: UserRef, target: ChannelRef) -> Option<Response> {
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_manage_channels() {
-        return Some(Response::LackingPermission(Permission::MANAGE_CHANNELS));
+        return Some(Response::LackingPermission(Permission::ManageChannels));
     }
 
     let col = database::get_collection("channels");
     match target.channel_type {
         0 => {
-            if col.update_one(
-                doc! { "_id": target.id },
-                doc! { "$set": { "active": false } },
-                None,
-            ).is_ok() {
+            if col
+                .update_one(
+                    doc! { "_id": target.id },
+                    doc! { "$set": { "active": false } },
+                    None,
+                )
+                .is_ok()
+            {
                 Some(Response::Result(super::Status::Ok))
             } else {
-                Some(Response::InternalServerError(json!({ "error": "Failed to close channel." })))
+                Some(Response::InternalServerError(
+                    json!({ "error": "Failed to close channel." }),
+                ))
             }
         }
         1 => {
@@ -109,7 +185,7 @@ pub fn messages(user: UserRef, target: ChannelRef) -> Option<Response> {
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_read_messages() {
-        return Some(Response::LackingPermission(Permission::READ_MESSAGES));
+        return Some(Response::LackingPermission(Permission::ReadMessages));
     }
 
     let col = database::get_collection("messages");
@@ -146,7 +222,7 @@ pub fn send_message(
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_send_messages() {
-        return Some(Response::LackingPermission(Permission::SEND_MESSAGES));
+        return Some(Response::LackingPermission(Permission::SendMessages));
     }
 
     let content: String = message.content.chars().take(2000).collect();
@@ -214,7 +290,7 @@ pub fn get_message(user: UserRef, target: ChannelRef, message: Message) -> Optio
     let permissions = with_permissions!(user, target);
 
     if !permissions.get_read_messages() {
-        return Some(Response::LackingPermission(Permission::READ_MESSAGES));
+        return Some(Response::LackingPermission(Permission::ReadMessages));
     }
 
     let prev =
@@ -317,7 +393,7 @@ pub fn delete_message(user: UserRef, target: ChannelRef, message: Message) -> Op
 
     if !permissions.get_manage_messages() {
         if message.author != user.id {
-            return Some(Response::LackingPermission(Permission::MANAGE_MESSAGES));
+            return Some(Response::LackingPermission(Permission::ManageMessages));
         }
     }
 
diff --git a/src/routes/guild.rs b/src/routes/guild.rs
index 9457a3e7965e9300862a4c6425f2a79a7928a291..3f8fdb817a5692d5894db4627f51a2d796c9f7c4 100644
--- a/src/routes/guild.rs
+++ b/src/routes/guild.rs
@@ -3,12 +3,11 @@ use crate::database::{
     self,
     channel::Channel,
     guild::{find_member_permissions, Guild},
-    user::User,
 };
 use crate::guards::auth::UserRef;
 
 use bson::{bson, doc, from_bson, Bson};
-use rocket_contrib::json::{Json, JsonValue};
+use rocket_contrib::json::Json;
 use serde::{Deserialize, Serialize};
 use ulid::Ulid;
 
@@ -126,7 +125,7 @@ pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
 
     let id = Ulid::new().to_string();
     let channel_id = Ulid::new().to_string();
-    if let Err(_) = channels.insert_one(
+    if channels.insert_one(
         doc! {
             "_id": channel_id.clone(),
             "type": ChannelType::GUILDCHANNEL as u32,
@@ -134,7 +133,7 @@ pub fn create_guild(user: UserRef, info: Json<CreateGuild>) -> Response {
             "guild": id.clone(),
         },
         None,
-    ) {
+    ).is_err() {
         return Response::InternalServerError(
             json!({ "error": "Failed to create guild channel." }),
         );
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
index 96a19ec65e29261745e79c34f48aff2456bb0a69..daee20884d7a18b3f4de28e3750721209f41b2e7 100644
--- a/src/routes/mod.rs
+++ b/src/routes/mod.rs
@@ -87,6 +87,7 @@ pub fn mount(rocket: Rocket) -> Rocket {
         .mount(
             "/api/channels",
             routes![
+                channel::create_group,
                 channel::channel,
                 channel::delete,
                 channel::messages,
diff --git a/src/routes/user.rs b/src/routes/user.rs
index 713043f0abcf828e5c6b6a468134ea3d2b5e7fb7..560580d3ac63deb38944e47119d932d6aad2ef02 100644
--- a/src/routes/user.rs
+++ b/src/routes/user.rs
@@ -64,7 +64,7 @@ pub fn lookup(user: UserRef, query: Json<Query>) -> Response {
         if let Ok(doc) = item {
             let id = doc.get_str("id").unwrap();
             results.push(json!({
-                "id": id.clone(),
+                "id": id,
                 "username": doc.get_str("username").unwrap(),
                 "relationship": get_relationship_internal(&user.id, &id, &relationships) as u8
             }));
@@ -174,11 +174,11 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
     let col = database::get_collection("users");
 
     match relationship {
-        Relationship::FRIEND => Response::BadRequest(json!({ "error": "Already friends." })),
-        Relationship::OUTGOING => {
+        Relationship::Friend => Response::BadRequest(json!({ "error": "Already friends." })),
+        Relationship::Outgoing => {
             Response::BadRequest(json!({ "error": "Already sent a friend request." }))
         }
-        Relationship::INCOMING => {
+        Relationship::Incoming => {
             if col
                 .update_one(
                     doc! {
@@ -187,7 +187,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
                     },
                     doc! {
                         "$set": {
-                            "relations.$.status": Relationship::FRIEND as i32
+                            "relations.$.status": Relationship::Friend as i32
                         }
                     },
                     None,
@@ -202,14 +202,14 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
                         },
                         doc! {
                             "$set": {
-                                "relations.$.status": Relationship::FRIEND as i32
+                                "relations.$.status": Relationship::Friend as i32
                             }
                         },
                         None,
                     )
                     .is_ok()
                 {
-                    Response::Success(json!({ "status": Relationship::FRIEND as u8 }))
+                    Response::Success(json!({ "status": Relationship::Friend as u8 }))
                 } else {
                     Response::InternalServerError(
                         json!({ "error": "Failed to commit! Try re-adding them as a friend." }),
@@ -221,10 +221,10 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
                 )
             }
         }
-        Relationship::BLOCKED => {
+        Relationship::Blocked => {
             Response::BadRequest(json!({ "error": "You have blocked this person." }))
         }
-        Relationship::BLOCKEDOTHER => {
+        Relationship::BlockedOther => {
             Response::Conflict(json!({ "error": "You have been blocked by this person." }))
         }
         Relationship::NONE => {
@@ -237,7 +237,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
                         "$push": {
                             "relations": {
                                 "id": target.id.clone(),
-                                "status": Relationship::OUTGOING as i32
+                                "status": Relationship::Outgoing as i32
                             }
                         }
                     },
@@ -254,7 +254,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
                             "$push": {
                                 "relations": {
                                     "id": user.id,
-                                    "status": Relationship::INCOMING as i32
+                                    "status": Relationship::Incoming as i32
                                 }
                             }
                         },
@@ -262,7 +262,7 @@ pub fn add_friend(user: UserRef, target: UserRef) -> Response {
                     )
                     .is_ok()
                 {
-                    Response::Success(json!({ "status": Relationship::OUTGOING as u8 }))
+                    Response::Success(json!({ "status": Relationship::Outgoing as u8 }))
                 } else {
                     Response::InternalServerError(
                         json!({ "error": "Failed to commit! Try re-adding them as a friend." }),
@@ -287,7 +287,7 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
     let col = database::get_collection("users");
 
     match relationship {
-        Relationship::FRIEND | Relationship::OUTGOING | Relationship::INCOMING => {
+        Relationship::Friend | Relationship::Outgoing | Relationship::Incoming => {
             if col
                 .update_one(
                     doc! {
@@ -332,8 +332,8 @@ pub fn remove_friend(user: UserRef, target: UserRef) -> Response {
                 )
             }
         }
-        Relationship::BLOCKED
-        | Relationship::BLOCKEDOTHER
+        Relationship::Blocked
+        | Relationship::BlockedOther
         | Relationship::NONE
         | Relationship::SELF => Response::BadRequest(json!({ "error": "This has no effect." })),
     }
diff --git a/src/websocket/mod.rs b/src/websocket/mod.rs
index 709c593f54655b58075892ee5d216b1bbe640c95..2563730477be2426805243749468fde2afedfce4 100644
--- a/src/websocket/mod.rs
+++ b/src/websocket/mod.rs
@@ -37,7 +37,7 @@ impl Handler for Server {
             if let Value::String(packet_type) = &data["type"] {
                 match packet_type.as_str() {
                     "authenticate" => {
-                        if let Some(_) = self.id {
+                        if self.id.is_some() {
                             self.out.send(
                                 json!({
                                     "type": "authenticate",
@@ -152,7 +152,7 @@ impl Handler for Server {
 
 pub fn launch_server() {
     unsafe {
-        if let Err(_) = CLIENTS.set(RwLock::new(HashMap::new())) {
+        if CLIENTS.set(RwLock::new(HashMap::new())).is_err() {
             panic!("Failed to set CLIENTS map!");
         }
     }