personal blog

Can you crack it ? Hell yeah!

5 months ago by Tadas in , (3 comments)

UK intelligence agency GCHQ challange… Can you crack it ?

Whilst browsing BBC website I found an article which caught my eye http://www.bbc.co.uk/news/technology-15968878. Basically UK intelligence agency GCHQ has launched a code-cracking competition to help attract new talent. I thought I’ll give it a try to see how complicated it is. And so it begun…

Warm up

Target: http://www.canyoucrackit.co.uk/ Ok first thing that was suspicios is why it is in a image format and not in plain text. So I had an assumption that something more is hidden in this image than just a simple text representation.  I loaded picture in different picture editors and tried to manipulate colors contrast and so on… However after wasting about an hour I had no idea what could it be. I felt like I was getting nowhere. However I found something in the image header. I used online exif viewer http://regex.info/exif.cgi?imgurl=http%3A%2F%2Fwww.canyoucrackit.co.uk%2Fimages%2Fcyber.png The comment field looked interesting.

QkJCQjIAAACR2PFtcCA6q2eaC8SR+8dmD/zNzLQC+td3tFQ4qx8O447T
DeuZw5P+0SsbEcYR78jKLw==

Even monkey can tell that it is Base64 coded data. So I decoded it and found something which was not making any sense at the moment. The string which starts with BBBB2…. Let’s leave it for awhile.

Digging deeper

Couldn’t find anything else interesting so I started digging data represented in the image. Some interesting string in the binary file …X=AAAAuCX=BBBBu (I can sense correlation between the data encoded in the image header and represented in the image) … However what really caught my eye is that it starts with 0xEB (which normally represent jmp instruction) at the end we have …0xcd 0×80 0×90 0×90 which would represent:

CD80 int 0x80
0x90 nop
0x90 nop

Made me think that this is a machine code. Let’s try to decompile it

ndisasm -b 32 code.bin > disasmcode.asm

produced me the following data:

00000000  EB04              jmp short 0x6
00000002  AF                scasd
00000003  C2BFA3            ret 0xa3bf
00000006  81EC00010000      sub esp,0x100
0000000C  31C9              xor ecx,ecx
0000000E  880C0C            mov [esp+ecx],cl
00000011  FEC1              inc cl
00000013  75F9              jnz 0xe
00000015  31C0              xor eax,eax
00000017  BAEFBEADDE        mov edx,0xdeadbeef
0000001C  02040C            add al,[esp+ecx]
0000001F  00D0              add al,dl
00000021  C1CA08            ror edx,0x8
00000024  8A1C0C            mov bl,[esp+ecx]
00000027  8A3C04            mov bh,[esp+eax]
0000002A  881C04            mov [esp+eax],bl
0000002D  883C0C            mov [esp+ecx],bh
00000030  FEC1              inc cl
00000032  75E8              jnz 0x1c
00000034  E95C000000        jmp dword 0x95
00000039  89E3              mov ebx,esp
0000003B  81C304000000      add ebx,0x4
00000041  5C                pop esp
00000042  58                pop eax
00000043  3D41414141        cmp eax,0x41414141
00000048  7543              jnz 0x8d
0000004A  58                pop eax
0000004B  3D42424242        cmp eax,0x42424242
00000050  753B              jnz 0x8d
00000052  5A                pop edx
00000053  89D1              mov ecx,edx
00000055  89E6              mov esi,esp
00000057  89DF              mov edi,ebx
00000059  29CF              sub edi,ecx
0000005B  F3A4              rep movsb
0000005D  89DE              mov esi,ebx
0000005F  89D1              mov ecx,edx
00000061  89DF              mov edi,ebx
00000063  29CF              sub edi,ecx
00000065  31C0              xor eax,eax
00000067  31DB              xor ebx,ebx
00000069  31D2              xor edx,edx
0000006B  FEC0              inc al
0000006D  021C06            add bl,[esi+eax]
00000070  8A1406            mov dl,[esi+eax]
00000073  8A341E            mov dh,[esi+ebx]
00000076  883406            mov [esi+eax],dh
00000079  88141E            mov [esi+ebx],dl
0000007C  00F2              add dl,dh
0000007E  30F6              xor dh,dh
00000080  8A1C16            mov bl,[esi+edx]
00000083  8A17              mov dl,[edi]
00000085  30DA              xor dl,bl
00000087  8817              mov [edi],dl
00000089  47                inc edi
0000008A  49                dec ecx
0000008B  75DE              jnz 0x6b
0000008D  31DB              xor ebx,ebx
0000008F  89D8              mov eax,ebx
00000091  FEC0              inc al
00000093  CD80              int 0x80
00000095  90                nop
00000096  90                nop
00000097  E89DFFFFFF        call dword 0x39
0000009C  41                inc ecx
0000009D  41                inc ecx
0000009E  41                inc ecx
0000009F  41                inc ecx

Quick code scan gave me impression that it IS a way to go as we can find instructions like

..
mov edx,0xdeadbeef
..
inc al
int 0x80; nice way to exit from the program.
..

We also have three nice loops. Let’s run it and see what happens.

char code[] =
"\xeb\x04\xaf\xc2\xbf\xa3\x81\xec\x00\x01\x00\x00\x31\xc9\x88\x0c"
"\x0c\xfe\xc1\x75\xf9\x31\xc0\xba\xef\xbe\xad\xde\x02\x04\x0c\x00"
"\xd0\xc1\xca\x08\x8a\x1c\x0c\x8a\x3c\x04\x88\x1c\x04\x88\x3c\x0c"
"\xfe\xc1\x75\xe8\xe9\x5c\x00\x00\x00\x89\xe3\x81\xc3\x04\x00\x00"
"\x00\x5c\x58\x3d\x41\x41\x41\x41\x75\x43\x58\x3d\x42\x42\x42\x42"
"\x75\x3b\x5a\x89\xd1\x89\xe6\x89\xdf\x29\xcf\xf3\xa4\x89\xde\x89"
"\xd1\x89\xdf\x29\xcf\x31\xc0\x31\xdb\x31\xd2\xfe\xc0\x02\x1c\x06"
"\x8a\x14\x06\x8a\x34\x1e\x88\x34\x06\x88\x14\x1e\x00\xf2\x30\xf6"
"\x8a\x1c\x16\x8a\x17\x30\xda\x88\x17\x47\x49\x75\xde\x31\xdb\x89"
"\xd8\xfe\xc0\xcd\x80\x90\x90\xe8\x9d\xff\xff\xff\x41\x41\x41\x41"
 
int main(void)
{(*(void(*)()) code)(); return 0;}

After executing code above it just “does” nothing. So I started to analyze the code.
Ok we have 3 loops which basically does key-sheduling and decrypting. And it looks like it is a RC4 implementation. However this peace of code tells something we are missing.

...
00000034  E95C000000        jmp dword 0x95
00000039  89E3              mov ebx,esp
0000003B  81C304000000      add ebx,0x4
00000041  5C                pop esp
00000042  58                pop eax
00000043  3D41414141        cmp eax,0x41414141
00000048  7543              jnz 0x8d
0000004A 58 pop eax 0000004B 3D42424242 cmp eax,0x42424242 00000050 753B jnz 0x8d
..

After executing call instruction we pop out the return address which is pointing to the end of our mystical data and we have 0×41414141 in the memory during execution. Everything makes sense until we try to pop from the stack to the eax register that would have to be 0×42424242. However we get nothing as we already reached the bottom. Clearly we are missing some data which should start 0×42424242 (BBBB). Luckily, we already have something from the image header. So I added the data to the existing code and tried to run again. Using gdb I could examine the memory after execution and found something interesting.

tadas@platoon:~/crack> gdb code
GNU gdb (GDB) SUSE (6.8.91.20090930-2.4)
Copyright (C) 2009 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i586-suse-linux".
For bug reporting instructions, please see:
...
Reading symbols from /home/tadas/crack/code...done.
(gdb) b *code+141
Breakpoint 1 at 0x804c08d
(gdb) r
Starting program: /home/tadas/crack/code
Missing separate debuginfo for /lib/ld-linux.so.2
Try: zypper install -C "debuginfo(build-id)=d7706cbaa0ca09319cb645eac789cb8399078797"
Missing separate debuginfo for /lib/libc.so.6
Try: zypper install -C "debuginfo(build-id)=ee302691046515fe3766ae3b7d47afd3e3a8d063"

Breakpoint 1, 0x0804c08d in code ()
(gdb) x/s $edi-0x32
0xbffff2da:      "GET /15b436de1f9107f3778aad525e5d0b20.js HTTP/1.1"
(gdb)

Oh yeah !!! Great feeling we found something what we were looking for… GET /15b436de1f9107f3778aad525e5d0b20.js HTTP/1.1. Although it took me a while to get familiar with the code and understand it I managed to pass the first level :)

Stage 2

http://www.canyoucrackit.co.uk/15b436de1f9107f3778aad525e5d0b20.js Got that script. Clear definition of the virtual machine which needs to be implemented. Nothing challenging just boring scripting to implement that VM. It took me hell a lot of time to implement it more than I thought and it’s nothing really interesting so I wouldn’t go into details. After completing this task I got another URL GET /da75370fe15c4148bd4ceec861fbdaa5.exe HTTP/1.0

Stage 3

So far good results has been achieved. I’ve downloaded executable which is windows executable. It’s interesting as the code in the stage 1 is written for linux and now we have windows binaries. So I tried to run it, however I got missing dll error. I was missing cygcrypt-0.dll. Well, it probably tells us that this piece of executable will do some sort of crypting/encrypting. Anyway, I downloaded all missing dll’s and tried to run again

C:\sandbox>da75370fe15c4148bd4ceec861fbdaa5.exe

keygen.exe
usage: keygen.exe hostname

C:\sandbox>da75370fe15c4148bd4ceec861fbdaa5.exe www.canyoucrackit.co.uk
keygen.exe

error: license.txt not found

Created empty license.txt file and tried again

keygen.exe

error: license.txt invalid

Pfuuhh…. Now I got impression that they are looking for people who are capable to write key generators :-) . So the next step is what we should place into the license.txt file to make this thing work. Quick look into the executable file showed many open strings

hqDTK7b8K2rvw
keygen.exe
 usage: keygen.exe hostname
 r license.txt error: license.txt not found
 %s  loading stage1 license key(s)...
   loading stage2 license key(s)...

 error: license.txt invalid
  error: gethostbyname() failed
 error: connect("%s") failed
 GET /%s/%x/%x/%x/key.txt HTTP/1.0

 request:

%s error: send() failed
 response:

Two strings looks interesting /%s/%x/%x/%x/key.txt and hqDTK7b8K2rvw. The first one probably is our answer we just need to replace %s and %x with correct values and second one looks like it is some sort of DES-based password hash. Anyway first of all I had to figure out what kind of stuff I have to put into the license.txt file to make this thing happy. After spending hours digging disassembled code I found out that first thing we need to put into the file is string which starts with gchq following by hqDTK7b8K2rvw decrypted password which is 8 characters long. Ok, so I started password cracker and continued my investigation. Instead of waiting password cracker to complete (it can take ages as we know it :) ) I did a bit of paching by replacing hqDTK7b8K2rvw with something I already know the answer like aaaaaaaa encrypted with salt hq and I’ve got hqWLFYOHRc1H6. Now my license file looks like this gchqaaaaaaaa.

keygen.exe

loading stage1 license key(s)...
loading stage2 license key(s)...

request:

GET /hqWLFYOHRc1H6/0/0/0/key.txt HTTP/1.0

response:

HTTP/1.0 404 Not Found

Hah it’s verifying password, however we don’t really need it ? As we can later replace with original one. So far so good… But still not valid and key.txt not found. Okey more debugging reviled that lincese.txt must contain extra data:

  • gchq
  • 8 character password (decrypted)
  • 4 bytes (stage 1) ?
  • 4 bytes (stage 2) ?
  • 4 bytes(stage 2) ?

So I did license.txt file gchqaaaaaaaa123412345678

GET /hqWLFYOHRc1H6/34333231/34333231/38373635/key.txt HTTP/1.0

It doe’s something but it’s not what I really want. I just have to figure out what info do I need. First thing I thought about is firmware in js file which I couldn’t figure out why they are and firmware is exactly 8 bytes long firmware: [0xd2ab1f05, 0xda13f110]. I placed into my licence.txt file and tried again. Fairly soon I got the idea how URL is constructed:

/hash/stage1(4 bytes in hex)/stage2(4 bytes in hex)/stage2(4 bytes in hex)/key.txt

And so it continues… I almost lost my hope and was nearly to gave up to guess the exact missing data and combination which would have to be inserted into the final URL. I was certain that firmware had to be used somewhere, however I was not sure that this data is our final answer to the problem (maybe it’s just a key or encrypted data) but I have no idea about stage 1 data. Tried many combinations. It was already very late and quiet night, so I thought I’ll make a pause and go for a walk to get some fresh air. After 30 minutes on my way back home I remembered that we have jmp instruction which leaves 4 bytes unused in this solution. Why would we want that? And we are searching for 4 bytes !. So I tried placing into my URL /hqDTK7b8K2rvw/a3bfc2af/d2ab1f05/da13f110/key.txt and got my answer (of course it took me some time trying different combinations)!! Yeahooo. Done. Great success! My final license.txt file looked like this:

67 63 68 71 61 61 61 61  61 61 61 61 AF C2 BF A3  05 1F AB D2 10 F1 13 DA

With my patched version it produces the following output:

C:\sandbox>patched.exe localhost

keygen.exe

loading stage1 license key(s)...
loading stage2 license key(s)...

request:

GET /hqWLFYOHRc1H6/a3bfc2af/d2ab1f05/da13f110/key.txt HTTP/1.0

response:

HTTP/1.0 404 Not Found

So I just replaced with original hash and that did the job.

And the final answer is Pr0t3ct!on#cyber_security@12*12.2011+

Conclusion

To sum it up I think the point of this challenge dividing it into stages was to test different skills:

  1. Stage 1 spot the data, try to understand the data, analyze it, glue it
  2. Stage 2 got the definition sit down implement the solution get your answer
  3. Stage 3 brute force and guessing

I think where could be more than one correct answer… Especially playing with URL in the last stage.
Personally Stage 1 was most interesting and challenging to me. And overall it took me 3 days to find the final solution.

Mind controlled helicopter

2 years ago by Tadas in , (6 comments)

My result of 5 years research in brain activity. See it for yourself :-) It works !

Basic theory. How our brains work

Our brains are filled with two classes of cells in the central nervous system, neurons and their support cells, called glia. The neuro’s basic parts are the cell body (soma), axon and dendrites. The cell body contains the organelles of the cell including the nucleus, Golgi apparatus (metabolic center), and the endoplasmic reticulum. A neuronal membrane covers the cell body protecting it from extracellular fluid. The dendrites are finger-like projections that extend out from the cell body. The dendrites serve as a long trunk, which can extend as far as 1m into the peripheral system. The end of the axon divides into many branches to form synaptic terminals. Most neurons are multipolar; that is, there is one axon with many dendrites. Multiple dendrites enable the cell to make contact with many other cells and thereby receive multiple inputs. Neurons communicate with each other by sending electrochemical signals from the synaptic terminal of one cell to the dendritic process of other cell.

In other words, we can think of our brains full of wires connected together and forms a huge network. And every time then we think about something or want to move, etc. electric signals travels thru this network. Although the paths the signals take are insulated by something called myelin, some of the electric signal escapes. Least invasive method to capture signals from the brain is done by attaching electrodes to the scalp – a device known as an electroencephalograph (EEG).  A typical adult human EEG signal is about 10µV to 100 µV in amplitude when measured from the scalp and is about 10–20 mV when measured from subdural electrodes. However it does have its drawback, the skull blocks a lot of the electrical signal, poor spatial resolution, dendrites which are deeper in the cortex has far less contribution to the EEG signal.

EEG signal

An EEG 1 second sample. The signal was acquired in the Oz position processed with scipy and exported with matplolib. The momntage was with common derivation related to linked ears. The sampling rate was 256 Hz. Created by Hugo Gamboa Dez 2005

An EEG 1 second sample. The signal was acquired in the Oz position processed with scipy and exported with matplolib. The momntage was with common derivation related to linked ears. The sampling rate was 256 Hz. Created by Hugo Gamboa Dez 2005

The EEG is typically described in terms of rhythmic activity and transients. The rhythmic activity is divided into bands by frequency. To some degree, these frequency bands are a matter of nomenclature (i.e., any rhythmic activity between 8–12 Hz can be described as “alpha”), but these designations arose because rhythmic activity within a certain frequency range was noted to have a certain distribution over the scalp or a certain biological significance. Frequency bands are usually extracted using spectral methods.

  • Theta is the frequency range from 4 Hz to 7 Hz. Theta is seen normally in young children. It may be seen in drowsiness or arousal in older children and adults; it can also be seen in meditation.
  • Alpha is the frequency range from 8 Hz to 12 Hz. This is activity in the 8–12 Hz range seen in the posterior regions of the head on both sides, being higher in amplitude on the dominant side. It is brought out by closing the eyes and by relaxation. It was noted to attenuate with eye opening or mental exertion.
  • Beta is the frequency range from 12 Hz to about 30 Hz. It is seen usually on both sides in symmetrical distribution and is most evident frontally. Beta activity is closely linked to motor behavior and is generally attenuated during active movements.
  • Gamma is the frequency range approximately 30–100 Hz. Gamma rhythms are thought to represent binding of different populations of neurons together into a network for the purpose of carrying out a certain cognitive or motor function.
  • Delta is the frequency range up to 4 Hz. It tends to be the highest in amplitude and the slowest waves. It is seen normally in adults in slow wave sleep.

Visualizing the current state of the brainwaves and providing a feedback in real time using video or sound can help to train your brains and improve mental performance.

Brain Computer Interface

An Electroencephalogram based Brain-Computer-Interface (BCI) provides a communication channel between the human brain and a computer. Having just a channel is not enough, as the EEG reflects thousands of simultaneously ongoing brain processes.

In short, read EEG signal, send to computer for processing, filter out all random brain processes and identify relevant information, that’s how it works!

Home made BCI

Here is my attempt to build one at home with the cheap home-made hardware. The biggest challenge for me (probably not only for me) was to average out random brain activity and remain only the relevant information. It took me more than three years to train to control brainwaves and measure brain response that is directly the result of a “thought”.

For my purpose I used 2 channel OpenEEG device with a bit of tweaking for extra processing before passing to computer. It works pretty unstable yet. You can see in the video that helicopter is jumping and is not flying very stable. My goal is to make it fly smoothly at least for a ten seconds, however currently I can control partly two channels of helicopter (total is 4) and command recognition is only about 20% accurate, but I need a better EEG device :)

References

For this article some text were taken from Wikipedia and book Introduction to Quantitative EEG and Neurofeedback.

Controlling your R/C toy from computer

2 years ago by Tadas in (6 comments)

Most of the RC toys (cars, helicopters, airplanes, etc.) have an easy way to connect to computer using training port. However this connection is only one way – from your transmitter to computer. Good option for practising your piloting skills using simulator. But I am not happy with only one way connection; I am too old to play with cheap R/C helicopter :-) I want more! I want to send signals from computer to transmitter and control my helicopter from PC and do some nice and sophisticated software :-) . Having a very cheap helicopter E-Sky co-comanche with supplied 4 channel 0404 transmitter which supports PPM signals,the easiest way I discovered so far is using PCTx interface.

So, how it works? The PCTx interface allows you to connect your R/C transmitter to your PC. By connecting an R/C transmitter to a PC via the PCTx interface, you now have the ability to take control of an R/C vehicle or robot with your PC side applications. Basically you get USB device and connect it to your training port, then simple software will do the trick. Officially the seller supports the following radio brands:

Sad, but E-sky transmitters are not in the list. However it is noted, that if your radio is not listed the PCTx may still work however it is not tested by Endurance R/C. If your transmitter has a trainer port and can accept a PPM signal then the PCTx should be compatible. Good news because my transmitter do have trainer port and accepts PPM signals! Another problem that listed plugs do not fit into my transmitter’s training port, but who cares as long as we know how to solder this should not be an issue, so those limitations did not stop me, I decided to give a try and ordered one. After waiting for almost one month due to fedex amazing delivery speed from US, finally I got one and started disassembling my transmitter to see how to hook PCTx to it. I was really surprised it was fairly easy to do so. Two wires from PCTx were red and black and two wires on the transmitter training port are red and black too! Just soldered wires together and it worked just fine!

Of course, hacking PPM signals and building own bridge between computer and transmitter would be much more fun, but maybe next time…

Glassfish 2 and Data push (Gravity)

2 years ago by Tadas in , , , , (0 comments)

It’s time to write a second post but something more useful and meaningful than just “hey I have a blog !” In the second post I’ll try to share my experience playing with graniteds and glassfish application server.

I am not going into details what is graniteds or flex, just a short text about gravity

Granite Data Services provides a Data Push feature, code name Gravity, implemented as a Comet-like service with AMF3 data polling over HTTP (producer/consumer based architecture). This implementation is freely based on the Bayeux protocol specification (1.0draft1 at this time).

Provided examples contains simple flex chat application which uses data push features and It worked fine for me, however I wanted to add some extra features, like simple web service which would publish a message to all connected clients and process messages inside message driven bean. So, what I had to do is to change flex services to use JMS Adapter instead of Simple Adapter, then create all necessary JMS stuff (topics, connection factories etc.) and then add simple web service which just basically publishes message to the created topic.

Shortly, I’ll try to walk thru all the steps which I have done to achieve my goal. First, we have to prepare glassfish server.

Create physical destination.

  • Go to admin console
  • Configuration > Java Message Service > Physical destinations
  • Press new
  • Name chat
  • Type java.jmx.Topic

Create connection factory

  • Go to Resources > JMS Resources > Connection factories
  • Press New
  • Fill in values
    • JNDI Name: jms/ChatConnectionFactory
    • Resource Type javax.jms.TopicConnectionFactory

Create destination resource

  • Go to Resources > JMS Resources > Destination Resources
  • Press new
    • JNDI Name: jms/ChatTopic
    • Physical destination: chat
    • Resource Type: javax.jms.Topic

We are done preparing glassfish with jms configuration. The next step is to create a simple web application with web service (very easy to achieve this using NetBeans). Simple create new web application (WebChat), then add new web service operation and send message to the newly created jms topic.

Here is my code

package lt.filosofija.mano.chat;
 
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.jws.Oneway;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
 
/**
 *
 * @author Tadas Danielius
 */
@WebService()
public class ChatService {
    @Resource(name = "jms/ChatTopic")
    private Topic chatTopic;
    @Resource(name = "jms/ChatConnectionFactory")
    private ConnectionFactory chatConnectionFactory;
 
    /**
     * Web service operation
     */
    @WebMethod(operationName = "Say")
    @Oneway
    public void Say(@WebParam(name = "text")
    String text) {
        try {
            sendJMSMessageToChatTopic("[Webservice] "+text);
        } catch (JMSException ex) {
            Logger.getLogger(ChatService.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
 
    private Message createJMSMessageForjmsChatTopic(Session session, Object messageData) throws JMSException {
        // TODO create and populate message to send
        TextMessage tm = session.createTextMessage();
        tm.setText(messageData.toString());
        return tm;
    }
 
    private void sendJMSMessageToChatTopic(Object messageData) throws JMSException {
        Connection connection = null;
        Session session = null;
        try {
            connection = chatConnectionFactory.createConnection();
            session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            MessageProducer messageProducer = session.createProducer(chatTopic);
            messageProducer.send(createJMSMessageForjmsChatTopic(session, messageData));
        } finally {
            if (session != null) {
                try {
                    session.close();
                } catch (JMSException e) {
                    Logger.getLogger(this.getClass().getName()).log(Level.WARNING, "Cannot close session", e);
                }
            }
            if (connection != null) {
                connection.close();
            }
        }
    }
 
}

folder structure

Service is ready!

Now goes all the flex stuff. Firstly we have to create extra folders and add configuration files for graniteds:

  1. WEB-INF/flex
  2. WEB-INF/granite
  3. WEB-INF/classes

Create configuration files

  1. flex/services-config.xml
  2. granite/granite-config.xml
  3. optionally you can put classes/log4j.xml and configure logging services.

Here is a screenshot how my folder structure looks like.

Here is my services-config.xml

 
 
 
 
 
 
 
 
 
 
                Topic
                javax.jms.TextMessage
                jms/ChatConnectionFactory
                jms/ChatTopic
		AUTO_ACKNOWLEDGE
false

Nothing special in granite-config.xml

 

Configure servlet in web.xml file

 
 
 
            30
 
 
 
        index.jsp
 
    GraniteDS EJB3
    GraniteDS EJB3 Demo Application
    <!-- Granite config context listener -->
 
org.granite.config.GraniteConfigListener
 
 
<span> </span>registerGraniteMBeans
<span> </span>true
 
 
        AMFMessageFilter
        org.granite.messaging.webapp.AMFMessageFilter
 
 
        AMFMessageFilter
        /graniteamf/*
 
 
        GravityServlet
        org.granite.gravity.generic.GravityGenericServlet
 
 
        GravityServlet
        /gravity/*

And don’t forget to add references all neccessary jar’s, like granite.jar

Chat client

 
<!--
  GRANITE DATA SERVICES
  Copyright (C) 2007-2008 ADEQUATE SYSTEMS SARL
 
  This file is part of Granite Data Services.
 
  Granite Data Services is free software; you can redistribute it and/or modify
  it under the terms of the GNU Lesser General Public License as published by
  the Free Software Foundation; either version 3 of the License, or (at your
  option) any later version.
 
  Granite Data Services is distributed in the hope that it will be useful, but
  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
  for more details.
 
  You should have received a copy of the GNU Lesser General Public License
  along with this library; if not, see <http://www.gnu.org/licenses />.
-->
 
 
 
 
    <![CDATA[
        import mx.events.ValidationResultEvent;
        import mx.messaging.events.MessageEvent;
        import mx.messaging.messages.AsyncMessage;
        import mx.utils.StringUtil;
 
        import org.granite.gravity.Consumer;
        import org.granite.gravity.Producer;
 
        [Bindable] private var nickname:String = "Anonymous";
        [Bindable] private var connected:Boolean = false;
 
        private var consumer:Consumer = null;
        private var producer:Producer = null;
 
        private var linesCount:int = 0;
        private var msgIndex:int = 1;
 
        private function connect():void {
            nickname = iNickname.text;
            if (nicknameValidator.validate().type === ValidationResultEvent.VALID) {
 
                consumer = new Consumer();
                consumer.destination = "chat-id";
                consumer.subscribe();
                consumer.addEventListener(MessageEvent.MESSAGE, messageHandler);
 
                producer = new Producer();
                producer.destination = "chat-id";
                var msg:AsyncMessage = new AsyncMessage();
                msg.body = '[' + nickname + ' has just connected]';
                producer.send(msg);
 
                connected = true;
            }
        }
 
        private function disconnect():void {
            consumer.disconnect();
            consumer = null;
 
            producer.disconnect();
            producer = null;
 
            linesCount = 0
            msgIndex = 1;
            vMessages.text = "";
            connected = false;
        }
 
        private function messageHandler(event:MessageEvent):void {
            var msg:AsyncMessage = event.message as AsyncMessage;
            var message:String = msg.body as String;
 
            if (linesCount >= 20) {
                var eol:int = vMessages.text.indexOf('\r');
                vMessages.text = vMessages.text.substring(eol + 1);
            }
 
            vMessages.text += '\r' + message;
            linesCount++;
        }
 
        private function send():void {
            var message:String = StringUtil.trim(iNewMessage.text);
            if (message.length > 0) {
                var msg:AsyncMessage = new AsyncMessage();
                msg.body = '[' + nickname + ' #' + (msgIndex++) + '] ' + message;
                producer.send(msg);
            }
            iNewMessage.text = "";
        }
    ]]>

We are done with the server side. Let’s move to the client side. Add new folder in src folder called flex and create new file chat.mxml. I took original chat.mxml file and did small changes to it. Here is my changed version

Compile mxml file

mxmlc -output ../../web/chat.swf -services ../../web/WEB-INF/flex/services-config.xml -context-root "/WebChat" -include-libraries granite-essentials.swc granite.swc -- Chat.mxml

Everything is ready to be deployed and tested !
Deploy and go to http://localhost:8080/WebChat/chat.swf
Test web service http://localhost:8080/WebChat/ChatServiceService?tester

Chat service test

And client side

Chat client

That’s it. Works fine. I hope this will be useful.

You can download WebChat source code

Go to Top