Skip to content

Instantly share code, notes, and snippets.

@hgaibor
Last active August 7, 2023 23:10
Show Gist options
  • Save hgaibor/6a170c150cf9dec607620aa44d78fcd0 to your computer and use it in GitHub Desktop.
Save hgaibor/6a170c150cf9dec607620aa44d78fcd0 to your computer and use it in GitHub Desktop.
targeted-chanSpy-with-levels-and-cos
; Feature code + Class of Service implementation to allow certain users to spy/whisper/barge on
; a specified extension.
; Additionally, levels of spy access have been included in the logic to create roles and restrict
; who can spy on what other roles based on a numeric level of access.
;
; Latest version:
; https://gist.github.com/hgaibor/6a170c150cf9dec607620aa44d78fcd0
;
; Forked from:
; https://gist.github.com/hgaibor/82433116540f15ab345b2914500abb0d
;
; Usage and install instructions:
; 1. On FreePBX/PBXact GUI, Create a Custom Destination that points to the [custom-spy-with-cos-and-levels] context.
; Fill the interface fields with the values after the --> :
; 1.1 Target --> custom-spy-with-cos-and-levels,s,1
; 1.2 Description --> Put a brief description
; 1.3 Notes --> Put your detailed comments here
; 1.4 Return --> no
;
; 2. Create a Misc Application that will point to created custom destination above.
; This destination will have the feature code you choose and will allow you to set the permissions over the
; Class of Service module.
; 2.1 Enable --> Yes
; 2.2 Description --> Spy with permissions feature code
; 2.3 Feature Code --> *557 (you can change this to whatever code needed)
; 2.4 Destination --> SELECT Custom Destination created above
;
; 3. Create Class of Service rules to DENY all users to use this code and allow the ones you need.
; Since you used the Misc Application module to assign the feature code, it will appear under the
; Class of Service --> [Feature codes] tab
;
; 4. Put Custom Dialplan at (GUI can be used using Config edit module):
; /etc/asterisk/extensions_custom.conf
; Dial feature code assigned under Misc Application to start in spy mode. While spying on
; active channel use the following dtmf input to toggle modes:
; dtmf 4 - spy mode
; 5 - whisper mode
; 6 - barge mode
;
; 5. Set the levels of permissions that can be used on each extension, in the 'accountcode' field at the [advanced] tab.
; extensions will be able to spy every other extension that have a lower numeric value on the accountcode,
; unless they are prevented from using the feature code by the Class of service module permissions.
;
; This is default behavior mentioned in https://wiki.asterisk.org/wiki/display/AST/Application_ChanSpy
;
; License: GNU GPL2
;
; Version History
; 2023-07-28 First public commit by hgaibor
; For testing spy level restrictions without COS, if you don't want to perform steps 1 to 3 mentioned above uncomment this
; block of code and use the code combination of your preference
;[from-internal-custom]
;exten => *557,1,Noop(Entering user defined context custom-spy-with-cos-and-levels in extensions_custom.conf)
;exten => *557,n,GoTo(custom-spy-with-cos-and-levels,s,1)
[custom-spy-with-cos-and-levels]
exten => s,1,Noop(Entering user defined context custom-spy-with-cos-and-levels in extensions_custom.conf)
; Get info on the originating extension
exten => s,n,Set(__SPY_EXT=${CALLERID(num)}) ; numeric spy level permission, will allow spy if this is greated than the SPIED_EXT accountcode value
exten => s,n,noop(Dialer Spy ext: ${SPY_EXT})
; Get info on the extension that will be spied
exten => s,n,Read(__SPIED_EXT,please-enter-the&extension&number&followed_pound)
exten => s,n,noop(Spied ext: ${SPIED_EXT})
exten => s,n,GoTo(check-access-level,s,1)
[check-access-level]
; This context will use the number set up in extensions Account Code in order to determine the level of spying access
; It will allow spying on levels that are lower than current extensions level
exten => s,1,Noop(Entering user defined context check-access-level in extensions_custom.conf)
exten => s,n,Set(SPY_LEVEL=${DB(AMPUSER/${SPY_EXT}/accountcode)}) ; Checking SPY level, will allow spy if greater than SPIED_LEVEL
exten => s,n,ExecIf($[!${LEN(${SPY_LEVEL})}]?Set(SPY_LEVEL=0))
exten => s,n,noop(Dialer spy level: ${SPY_LEVEL})
; Checking SPIED_EXT spy level
exten => s,n,Set(SPIED_LEVEL=${DB(AMPUSER/${SPIED_EXT}/accountcode)}) ; numeric spy level permission, will allow spy if greater than
exten => s,n,ExecIf($[!${LEN(${SPIED_LEVEL})}]?Set(SPIED_LEVEL=0))
exten => s,n,noop(Spied ext level: ${SPIED_LEVEL})
;Checking if SPY extension can monitor SPIED extension
exten => s,n,GotoIf($[${SPY_LEVEL}>${SPIED_LEVEL}]?AllowSpy:DenySpy)
exten => s,n,Hangup()
exten => s,n(AllowSpy),noop(Allowed spy from ext ${SPY_EXT} to ${SPIED_EXT})
exten => s,n,GoTo(targeted-chanspy,${SPIED_EXT},1)
exten => s,n,Hangup()
exten => s,n(DenySpy),noop(DENIED! spy from ext ${SPY_EXT} to ${SPIED_EXT})
exten => s,n,Playback(silence/1&sorry-cant-let-you-do-that&silence/1)
exten => s,n,Hangup()
exten => h,n,Hangup()
exten => s,n,Hangup()
exten => T,n,Hangup() ; timeout destination
[targeted-chanspy]
exten => _.,1,Noop(Entering user defined context targeted-chanspy in extensions_custom.conf)
exten => _.,n,Set(TIMEOUT(absolute)=3600) ; prevent hung channel by setting 1 hour timeout recommended if using infinite loop
exten => _.,n,Answer
exten => _.,n(once-upon-a-time),Wait(1)
exten => _.,n,set(spy_target=) ; initialize target var
; get list of dialable devices for extension
exten => _.,n,Set(DEVS=${DB(AMPUSER/${EXTEN}/device)}) ; & delimited list of devices
exten => _.,n,Set(DEVS=${STRREPLACE(DEVS,&,\,)}) ; comma delimited list of devices
; step thru each device and look for an active channel
exten => _.,n,While($["${SET(DEV=${POP(DEVS)})}" != ""])
exten => _.,n,noop(dev: ${DEV})
; using a regex of SIP/${EXTEN}- will match both SIP and PJSIP channels, and the trailing - character should
; help to ensure there is only a single match. If multiple channels are returned the chanspy application will fail
exten => _.,n,set(spy_target=${CHANNELS(SIP/${DEV}-)})
exten => _.,n,ExecIf($["${spy_target}"!=""]?ExitWhile) ; if an active channel is found exit the loop
exten => _.,n,EndWhile()
exten => _.,n,ExecIF($["${spy_target}"!=""]?ChanSpy(${spy_target},dnqE)) ; q option suppresses channel announce on barge
exten => _.,n,Hangup() ;comment this line with a semicolon to do infinite loop
exten => _.,n,GoTo(once-upon-a-time)
exten => _.,n,Hangup()
exten => h,n,Hangup()
exten => s,n,Hangup()
exten => T,n,Hangup() ; timeout destination
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment