|
33, Alexander Malinov Blvd., Sofia, 1729, Bulgaria
Phone: (+359) 2 80-99-862; Fax: (+359) 2 80-99-888
|
|
Crypto-Chat – курсов проект по
„Уеб дизайн с HTML 5, CSS 3 и JavaScript – част II" – вариант #1
Да се проектира и реализира клиентско уеб приложение за криптиран чат. В него потребителите разменят чат съобщения по между си, които се криптират с предварително уговорен между тях споделен ключ. Криптирането и декриптирането се извършва от страната на клиента и чат съобщенията не могат да се разкодират на сървъра.
Описание на системата "Crypto-Chat"
Посредством централен сървър потребителите в системата "Crypto-Chat" могат да се регистрират, да влизат в системата и да изпращат и получават криптирани съобщения по между си. За целта всяка двойка потребители уговарят предварително таен ключ, с който се кодират съобщенията по между си. Сървърът само прехвърля криптираните съобщения, но не е в състояние да ги декодира, тъй като няма достъп до уговорените между потребителите ключове. Тези ключове се уговарят при среща на живо между потребителите без възможност за "прихващане" по електронен път. Криптографията е базирана на стандартен криптоалгоритъм (AES-128).
Работа на системата "Crypto-Chat"
Работата със системата "Crypto-Chat" най-общо обхваща следните стъпки:
-
Посетителите в системата могат свободно да се регистрират.
-
Регистрираните потребители могат да влязат в системата (login).
-
След влизане в системата потребителите виждат всички онлайн потребители и могат да ги канят на криптирани чат дискусии.
-
Потребителите, влезли в системата, могат да получават покани за чат дискусии от останалите потребители.
-
Отварянето на чат дискусия се извършва в три стъпки по следната challenge-response схема:
-
При иницииране на чат дискусия потребителят-инициатор въвежда тайния ключ за чат с другия потребител и към сървъра се изпраща случайно число криптирано с този ключ (challenge).
-
При получаване на покана за чат дискусия потребителят-получател въвежда тайния ключ за чат с другия потребител, декриптира с него полученото challenge число, преобразува го по определена формула, след което го криптира с тайния ключ и го изпраща като отговор на инициатора на чата (response).
-
При получаване на криптирания response, инициаторът на чата установява математически дали поканеният на чат потребител използва същия таен ключ като него и ако е така, стартира чат сесия между двамата.
-
Потребителите, между които има активна чат сесия, могат да си пращат криптирани съобщения, използвайки тайния ключ, който и двамата знаят.
-
Потребителите могат да затварят своите чат сесии по всяко време.
-
Влезлите в системата потребители могат да излязат от нея по всяко време (logout).
Архитектура на системата "Crypto-Chat"
Системата "Crypto-Chat" за криптиран чат в реално време работи в режим клиент-сървър. Клиентите комуникират по между си през сървъра (не директно) чрез изпращане на REST заявки с JSON-сериализирани данни.
Комуникация със сървъра
Цялата комуникация между клиента и сървъра се извършва в REST стил чрез HTTP GET и HTTP POST команди, изпратени асинхронно като AJAX заявки от клиента към сървъра, на които сървърът отговаря с JSON-сериализиран резултат. При успех сървърът връща HTTP статус код 200, а при грешка връща трицифрен HTTP статус код за грешка. Форматът на всяка REST заявка е различен и е описан по-долу, като URL адресът на REST услугата е условно означен по следния начин:
Услугите от страна на сървъра се разработват от преподавателския екип и не са задача на курсистите. Услугите се предоставят във вид на сорс код + скрипт за създаване на базата данни и могат да се ползват локално или от Интернет. Публичната Интернет инстанция на сървърната REST услуга за проекта е достъпна от следния URL в облака на AppHarbor:
http://cryptochat.apphb.com/CryptoChatService.svc
|
Всеки участник сам преценява дали да ползва публичния Интернет сървър или да инсталира собствено локално копие (ако има технически познания и желание да го направи).
Имайте предвид, че тъй като заявките и резултатите от извикване на REST услугите са стандартни JSON-сериализирани обекти, няма гаранция за наредбата на ключовете в асоциативните масиви, които се връщат или изпращат (тя може да е произволна).
Регистрация
Регистрацията в системата е отворена публично за всички посетители на клиентското уеб приложение. При регистрация към сървъра се изпраща потребителско име и автентикационен код. Автентикационният код се изчислява чрез хеширане на потребителското име и паролата (долепени едно до друго) по формулата SHA1(username + password) и се изпраща като шестнайсетично число. Формат на заявката към услугата:
URL
|
http://service-url/register
|
Method: POST
|
Body
|
{"username":"bob","authCode":"8bcac5dabf06219843a5a3b755c47e69600e050a"}
|
Потребителското име трябва да е непразен низ до 30 символа, съдържащо единствено букви, цифри и знаците ".", "-" и "_". Потребителските имена трябва да са уникални в рамките на системата.
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf"}
|
Стойността в полето sessionID е идентификатор (стринг до 50 символа), който представлява уникален номер на установена потребителска сесия. При неактивност от 5 минути сесията става невалидна и всеки опит да се използва ще върне грешка.
При успешна регистрация новорегистрираният потребител се счита за влязъл в системата (без да се изпълнява login). Сървърът изпраща към всички онлайн потребители съобщение за нов потребител, който е онлайн.
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"erorrCode":"ERR_DUPLICATE","errorMsg":"Duplicated username"}
|
Текстът в полето errorMsg е само информативен и не е предназначен за машинна обработка. Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
404
|
ERR_DUPLICATE
|
Duplicated username
|
404
|
ERR_USR_NAME
|
Invalid username
|
404
|
ERR_AUTH_CODE
|
Invalid authCode (it should be exactly 40 hexadecimal digits)
|
500
|
ERR_GENERAL
|
User registration failed (general error)
| Вход в системата (login)
Входът в системата се извършва по потребителско име и автентикационен код. Автентикационният код се изчислява чрез хеширане на въведените от потребителя потребителско име и парола (долепени едно до друго) по формулата SHA1(username + password) и се изпраща като шестнайсетично число. Формат на заявката към услугата:
URL
|
http://service-url/login
|
Method: POST
|
Body
|
{"username":"bob","authCode":"8bcac5dabf06219843a5a3b755c47e69600e050a"}
|
При успех услугата връща HTTP статус код 200 и резултат в същия формат като при регистрацията:
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf"}
|
При успешен вход в системата сървърът изпраща към всички онлайн потребители нотификация за успешно влизане на потребителя, извършил login операцията.
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_INV_LOGIN","errorMsg":"Invalid username or password"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_INV_LOGIN
|
Invalid username or password
|
404
|
ERR_AUTH_CODE
|
Invalid authCode (it should be exactly 40 hexadecimal digits)
|
500
|
ERR_GENERAL
|
Login failed (general error)
| Изход от системата (logout)
Изходът от системата се извършва по идентификатор на потребителска сесия sessionID, който се подава като параметър. Формат на заявката към услугата:
URL
|
http://service-url/logout/sessionID
|
Method: GET
|
При успех услугата връща HTTP статус код 200 и следния резултат:
При успешен изход от системата сървърът изпраща към всички онлайн потребители съобщение за потребителя, който е излязъл от системата и вече е офлайн.
Сървърът изпраща съобщения за излизане на потребител и при изтичане на неговата сесия.
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_LOGOUT_FAIL","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
500
|
ERR_GENERAL
|
Logout failed (general error)
| Извличане на всички онлайн потребители
Извличането на всички онлайн потребители е позволено само за автентикирани потребители. Сървърът счита за онлайн всички потребители, които са извършили някакво взаимодействие със системата през последните 5 минути. Формат на заявката към услугата:
URL
|
http://service-url/list-users/sessionID
|
Method: GET
|
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
Body
|
["alan","bob","jane","mary","pepi","tanya"]
|
В посоченият списък ще присъства и потребителят, отправил заявката към услугата (той със сигурност е онлайн в този момент).
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
500
|
ERR_GENERAL
|
Listing online users failed (general error)
| Изпращане на покана за чат със секретен ключ (challenge)
Всеки автентикиран потребител може да кани на чат онлайн потребителите от системата. При изпращане на покана за чат потребителят въвежда тайния ключ K за чат с избрания потребител. След това се генерира случайно число R в интервала [0 … 999 999 999]. Към сървъра се изпраща кодираният текст challenge = AES(R, K) и името на потребителя, за който е поканата. Формат на заявката към услугата:
URL
|
http://service-url/invite-user
|
Method: POST
|
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf","recipientUsername":"bob","challenge": "U2FsdGVkX19EHlN+m0PFy/8upS/lcPyxf21mTRpjPTA="}
|
Можете да използвате имплементацията gibberish-aes.js на AES алгоритъма, в която има готова функция за криптиране и декриптиране на произволен текст по даден ключ (ключът също е произволен текст) и връща резултата като блок от байтове, кодиран по стандарта BASE64.
При успех услугата връща HTTP статус код 200 и следния резултат:
Даден потребител може да кани на чат даден друг потребител (който е онлайн) по всяко време. След изпращане на покана статусът на чата между първия и втория потребител преминава в режим "изпратена покана" и сървърът изпраща поканата към посочения потребител. Една покана важи докато бъде приета или сесията на някой от двамата потребителя изтече. Изпращането на покана от един потребител към друг изтрива всякакви установени преди това или частично установени чат сесии между двамата потребители.
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
404
|
ERR_BAD_USER
|
Invalid username
|
404
|
ERR_USER_OFF
|
The specified recipient user is offline
|
404
|
ERR_AUTO_CHAT
|
Users cannot send chat invitations to themselves
|
404
|
ERR_BAD_CHALL
|
Invalid challenge code. It should be BASE64-encoded encrypted data
|
500
|
ERR_GENERAL
|
Cannot invite the specified user to chat (general error)
| Отговор на покана за чат със секретен ключ (response)
Всеки автентикиран потребител може да получи покана за чат от друг потребител в системата. При получаване на покана, той може да я приеме или отхвърли (да откаже чат сесията).
За да приеме дадена покана за чат, потребителят въвежда тайния ключ K за чат с потребителя, изпратил поканата. Полученият challenge се декриптира с ключа K и се получава случайно генерираното число на поканващия потребител (числото R, което трябва да е целочислена стойност в интервала [0 … 999 999 999]). След това се изчислява числото отговор на поканата response = AES(999 999 999 – R, K) и се изпраща към сървъра, за да бъде обработено от потребителя, който е отправил поканата. Формат на заявката към услугата:
URL
|
http://service-url/response-chat-invitation
|
Method: POST
|
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf","recipientUsername":"bob","response": "U2FsdGVkX18h/HyLfbQU73SzKZh6e3+IbYXUDL4vUOs="}
|
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
След изпращане на отговор на покана статусът на чата между първия и втория потребител преминава в режим "изпратен отговор". Сървърът автоматично изпраща отговора на поканата към посочения потребител.
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
404
|
ERR_BAD_USER
|
Invalid username
|
404
|
ERR_USER_OFF
|
The specified recipient user is offline
|
404
|
ERR_BAD_RESP
|
Invalid response code. It should be BASE64-encoded encrypted data
|
404
|
ERR_INVALID_STATE
|
No open invitation exists for the specified user
|
500
|
ERR_GENERAL
|
Cannot accept invitation (general error)
| Начало на чат сесия
Когато даден потребител получи отговор на покана за чат от друг потребител, той може да провери дали отговорът е валиден. Това става като се декриптира response кодът с тайния ключ K за чат между двамата потребители. Ако той е валиден (т.е. полученият декодиран отговор съдържа стойността 999 999 999 – R), се стартира чат сесия. Иначе чат сесията се отказва.
Стартирането на чат сесия трябва да се извършва само когато двамата потребители са преминали успешно challenge-response процеса. Този процес гарантира, че двамата ползват един и същ ключ K за криптиране на чат съобщенията. За стартиране на чат сесия се използва услугата:
URL
|
http://service-url/start-chat
|
Method: POST
|
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf","recipientUsername":"bob"}
|
След изпращане на отговор на покана статусът на чата между първия и втория потребител в системата преминава в режим "активен". Сървърът автоматично изпраща известие за начало на чат към другия потребител.
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
404
|
ERR_BAD_USER
|
Invalid username
|
404
|
ERR_USER_OFF
|
The specified recipient user is offline
|
404
|
ERR_INVALID_STATE
|
No valid invitation response exists for the specified user
|
500
|
ERR_GENERAL
|
Cannot start chat (general error)
| Отказ на чат сесия
Когато даден потребител получи отговор на покана за чат от друг потребител, той може да провери дали отговорът е валиден (т.е. дали двамата потребители ползват еднакъв таен ключ K). Ако ключовете на двамата потребители не съвпадат, чат сесията се отказва. Чат сесия може да се откаже (прекрати) и по всяко друго време. За отказване на чат сесия се използва услугата:
URL
|
http://service-url/cancel-chat
|
Method: POST
|
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf","recipientUsername":"bob"}
|
След отказване на чат сесия статусът на чата между първия и втория потребител в системата преминава в режим "невалиден" (какъвто е в началото, когато потребителят влезе в системата). Сървърът автоматично изпраща известие за начало на чат към другия потребител.
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
404
|
ERR_BAD_USER
|
Invalid username
|
404
|
ERR_USER_OFF
|
The specified recipient user is offline
|
500
|
ERR_GENERAL
|
Cannot cancel chat (general error)
| Изпращане на криптирано съобщение
След като e успешно отворена чат сесия между двама автентикирани потребители и е потвърдено, че двамата ползват един и същ таен ключ К за криптиране на чат съобщенията, всеки от тях може да изпраща на другия съобщения, криптирани с ключа К.
При изпращане на съобщение Msg, то се въвежда от потребителя като чист текст и се кодира преди да се изпрати: encryptedMsg = AES(Msg, K). Формат на заявката към услугата:
URL
|
http://service-url/send-chat-message
|
Method: POST
|
Body
|
{"sessionID":"wj8kmcdiu63hhe6t3g2623gf","recipientUsername":"bob", "encryptedMsg":"U2FsdGVkX19CMOlDRrQCHd/Pc/zMhk3+oK19X/DL0+A="}
|
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
След като едно съобщение е изпратено към сървъра за даден потребител, то ще бъде получено от него в момента, в който потребителят-получател поиска от сървъра своите съобщения.
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
404
|
ERR_BAD_USER
|
Invalid recipient username
|
404
|
ERR_USER_OFF
|
The specified recipient user is offline
|
404
|
ERR_BAD_MSG
|
Invalid encrypted message
|
404
|
ERR_INVALID_STATE
|
No active chat session exists with the specified recipient user
|
500
|
ERR_GENERAL
|
Cannot send the message (general error)
| Получаване на съобщения от сървъра
Клиентското чат приложение може да получава съобщения от сървъра по всяко време. Тези съобщения могат да бъдат информативни (например, че даден потребител е online или offline), свързани с установяване на чат сесия (challenge, response, начало / отказ на чат) или криптирани чат съобщения.
Клиентът извлича своите съобщения от сървъра чрез асинхронни AJAX заявки, които отправя през определено време (например през 500 милисекунди) чрез услугата за извличане на съобщения. Съобщенията се трупат в опашка на сървъра, в реда, в който са възникнали и се губят при logout на потребител или при унищожаване на сесията му. Формат на заявката към услугата:
URL
|
http://service-url/get-next-message/sessionID
|
Method: GET
|
При едно извикване услугата връща поредното съобщение от сървъра или информация, че няма чакащи съобщения, които все още не са били извлечени. Ако на сървъра има повече от едно чакащо съобщение, услугата трябва да се извика няколко пъти, за да ги прочете едно по едно.
При успех услугата връща HTTP статус код 200 и резултат в следния формат:
Body
|
{"msgType":"MSG_INVITE","username":"bob","msgText":"some text"}
|
Ако на сървъра няма чакащи съобщения за текущия потребител, резултатът е следният:
Body
|
{"msgText":null,"msgType":"MSG_NO_MESSAGES","username":null}
|
Кодовете на получените съобщения в полето msgType и съответната им логическа интерпретация са както следва:
MsgType
|
Description
|
MSG_NO_MESSAGES
|
There are no messages waiting on the server
|
MSG_USER_ONLINE
|
The specified username just performed "login" in the system
|
MSG_USER_OFFLINE
|
The specified username just performed "logout " from of the system or his session has just expired due to inactivity
|
MSG_CHALLENGE
|
The specified username sent an initial chat invitation (its challenge code is contained in the msgText field)
|
MSG_RESPONSE
|
The specified username sent a response to a chat invitation (its response code is contained in the msgText field)
|
MSG_START_CHAT
|
The specified username started a chat session with the current user
|
MSG_CANCEL_CHAT
|
The specified username canceled to a chat invitation or а chat session with the current user
|
MSG_CHAT_MESSAGE
|
The specified username sent an encrypted chat message to the current user
|
При грешка услугата връща трицифрен HTTP статус код за грешка и резултат в следния формат:
Body
|
{"errorCode":"ERR_SESSIONID","errorMsg":"Invalid sessionID"}
|
Кодовете на грешките в полето errorCode са следните:
HTTP Code
|
Error Code
|
Description
|
403
|
ERR_SESSIONID
|
Invalid sessionID
|
500
|
ERR_GENERAL
|
Cannot get the message from the server (general error)
|
При получаване на съобщения клиентското чат приложението само преценява как да ги обработи и как да реагира. Например при login / logout на потребител, той може да се добави или изтрие от списъка с потребители. При получаване на чат покана, отговор на покана, начало на чат или при получаване на чат съобщение екранът за чат с този потребител трябва да визуализира това по някакъв начин (смяна на цвят / шрифт / визуален ефект / допълнителен текст или друг начин).
Обработка на грешки
Клиентското чат приложение трябва да обработва евентуално възникващите грешки по подходящ начин, например да има специален екран (прозорец) за тях или да ги визуализира в специално поле или по друг начин. Грешки могат да възникнат по всяко време и по най-различни причини: прекъснат достъп до Интернет, изгубена връзка със сървъра, грешка на сървъра, изпратена невалидна команда, изпратена команда към потребител, който вече не е онлайн, получено невалидно съобщение, получено съобщение криптирано с грешен ключ и т.н.
Допълнителни изисквания -
Потребителският интерфейс на системата може да е на български или на английски език (по ваш избор).
-
Приложението трябва да е базирано на HTML5 и JavaScript. По желание може да се използва jQuery или друг JavaScript framework.
-
Нямате право да използвате сървърна логика, която се различава от предоставената имплементация на услугите към проекта. Нямате право да добавяте допълнителни сървърни услуги.
-
Трябва да се поддържат следните уеб браузъри: Chrome 16+, Firefox 9+, IE9+, Safari 5.1+.
Бонуси
Допълнителни точки ще се дават за:
-
Реализирана добра ползваемост – удобен, лесен за употреба и интуитивен потребителски интерфейс.
-
Коректност и правилна работа при необичайни ситуации: например при въвеждане на невалидни данни (празни полета, прекалено дълги полета, невалиден формат).
-
Качествен програмен код (HTML, CSS, JavaScript), структуриране на програмната логика в класове, функции и файлове, спазвайки утвърдените в индустрията концепции за изграждане на качествен софтуер.
-
Добър и удобен външен вид (уеб дизайн) – можете да ползвате ваш собствен дизайн или да адаптирате дизайн със свободен лиценз.
-
Реализирането на функционалност, която не се изисква в условията на проектите не носи непременно допълнителни точки. По-важно е да се реализира коректно и качествено изискваната функционалност.
Предаване на проектите
Проектите се предават като цялостно реализирано клиентско уеб приложение. Курсовият проект изисква да бъдат предадени следните активи (пакетирани в ZIP или RAR архив):
-
HTML код на приложението
-
JavaScript код на приложението (ако използвате външни JavaScript библиотеки, може да включите техния сорс код или да ги ползвате от Интернет)
-
CSS код на приложението
-
Други незадължителни активи (Photoshop файл с уеб дизайна например, инструкции за употреба, документация и т.н.)
Проектите се предават онлайн от формата за изпращане на домашни и проекти към курса: http://telerikacademy.com/Courses/Courses/Details/10.
Краен срок за предаване на проектите: 10 февруари 2013 г.
Защита на проектите
Защитата на проектите ще се извърши в края на курса. На защитата всеки студент ще трябва да представи проекта си, да покаже каква част от изискванията са реализирани и работят и да разкаже как е реализирал функционалността, след което ще му бъде дадена задача – да реализира допълнителна функция към проекта, на място в изпитната зала.
Силно препоръчително е всеки да си носи лаптоп с подготвена работна среда, на който да работи по време на защитата или да използва отдалечена сесия до своя работен настолен компютър.
За да спестите време по време на защитата моля подгответе достатъчно примерни данни в базата данни на вашата система, с които да покажете всичките й функции в действие. Например, за да покажете страниране на таблици, е необходимо да имате подготвени достатъчно данни в съответната таблица.
|
Deliver more than expected
|
Page of
|
www.telerik.com
|
Сподели с приятели: |